diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index f2b3950bfb..1022423a49 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,9 @@ ### New features since last release +* Add dynamic linking to LAPACK/OpenBlas shared objects in scipy.libs for both C++ and Python layer. + [(#651)](https://github.com/PennyLaneAI/pennylane-lightning/pull/651) + * `lightning.qubit` supports mid-circuit measurements. [(#650)](https://github.com/PennyLaneAI/pennylane-lightning/pull/650) @@ -29,6 +32,9 @@ ### Breaking changes +* Deprecate static LAPACK linking support. + [(#651)](https://github.com/PennyLaneAI/pennylane-lightning/pull/651) + * Migrate `lightning.qubit` to the new device API. [(#646)](https://github.com/PennyLaneAI/pennylane-lightning/pull/646) @@ -60,7 +66,7 @@ This release contains contributions from (in alphabetical order): -Ali Asadi, Amintor Dusko, Christina Lee, Vincent Michaud-Rioux, Mudit Pandey +Ali Asadi, Amintor Dusko, Christina Lee, Vincent Michaud-Rioux, Mudit Pandey, Shuli Shu --- diff --git a/.github/workflows/tests_gpu_cuda.yml b/.github/workflows/tests_gpu_cuda.yml index d3abac6937..1613b02fe9 100644 --- a/.github/workflows/tests_gpu_cuda.yml +++ b/.github/workflows/tests_gpu_cuda.yml @@ -11,7 +11,7 @@ on: required: true description: The version of PennyLane to use. Valid values are either 'release' (most recent release candidate), 'stable' (most recent git-tag) or 'latest' (most recent commit from master) release: - pull_request: + #pull_request: push: branches: - master @@ -130,7 +130,6 @@ jobs: cmake . -BBuild \ -DCUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum')")\ -DBUILD_TESTS=ON \ - -DENABLE_LAPACK=ON \ -DENABLE_PYTHON=OFF \ -DPL_BACKEND=${{ matrix.pl_backend }} \ -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) \ diff --git a/.github/workflows/tests_gpu_kokkos.yml b/.github/workflows/tests_gpu_kokkos.yml index c31488ad40..9307781c3f 100644 --- a/.github/workflows/tests_gpu_kokkos.yml +++ b/.github/workflows/tests_gpu_kokkos.yml @@ -10,7 +10,7 @@ on: type: string required: true description: The version of PennyLane to use. Valid values are either 'release' (most recent release candidate), 'stable' (most recent git-tag) or 'latest' (most recent commit from master) - pull_request: + #pull_request: push: branches: - master diff --git a/.github/workflows/tests_linux.yml b/.github/workflows/tests_linux.yml index a6373a8111..23fe4e7e05 100644 --- a/.github/workflows/tests_linux.yml +++ b/.github/workflows/tests_linux.yml @@ -10,7 +10,7 @@ on: type: string required: true description: The version of PennyLane to use. Valid values are either 'release' (most recent release candidate), 'stable' (most recent git-tag) or 'latest' (most recent commit from master) - pull_request: + #pull_request: push: branches: - master @@ -47,14 +47,15 @@ jobs: uses: actions/checkout@v3 - name: Install dependencies - run: echo ${{ github.event_name }} && sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION liblapack-dev ninja-build gcovr lcov + run: | + echo ${{ github.event_name }} && sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION ninja-build gcovr lcov + python -m pip install scipy - name: Build and run unit tests run: | cmake . -BBuild -G Ninja \ -DCMAKE_BUILD_TYPE=Debug \ -DBUILD_TESTS=ON \ - -DENABLE_LAPACK=ON \ -DENABLE_PYTHON=OFF \ -DPL_BACKEND=${{ matrix.pl_backend }} \ -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) \ @@ -111,6 +112,11 @@ jobs: runs-on: ${{ matrix.os }} steps: + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: '3.9' + - name: Checkout PennyLane-Lightning uses: actions/checkout@v3 with: @@ -133,13 +139,10 @@ jobs: git log -1 --format='%H' git status - - uses: actions/setup-python@v4 - name: Install Python - with: - python-version: '3.9' - - name: Install dependencies - run: sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION + run: | + sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION + python -m pip install scipy - name: Get required Python packages run: | @@ -218,7 +221,9 @@ jobs: uses: actions/checkout@v3 - name: Install dependencies - run: sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION liblapack-dev libopenblas-dev ninja-build gcovr lcov + run: | + sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION libopenblas-dev ninja-build gcovr lcov + python -m pip install scipy - name: Build and run unit tests run: | @@ -228,7 +233,6 @@ jobs: -DENABLE_BLAS=ON \ -DPL_BACKEND=${{ matrix.pl_backend }} \ -DBUILD_TESTS=ON \ - -DENABLE_LAPACK=ON \ -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) \ -DENABLE_COVERAGE=ON cmake --build ./Build @@ -237,62 +241,6 @@ jobs: for file in *runner ; do ./$file --order lex --reporter junit --out ./tests/results/report_$file.xml; done; lcov --directory . -b ../pennylane_lightning/core/src --capture --output-file coverage.info lcov --remove coverage.info '/usr/*' --output-file coverage.info - mv coverage.info coverage-${{ github.job }}-${{ matrix.pl_backend }}-Lapack.info - - - name: Upload test results - uses: actions/upload-artifact@v3 - if: always() - with: - name: ubuntu-tests-reports-${{ github.job }}-${{ matrix.pl_backend }}-Lapack - path: ./Build/tests/results/ - if-no-files-found: error - - - name: Upload code coverage results - uses: actions/upload-artifact@v3 - with: - name: ubuntu-codecov-results-cpp - path: ./Build/coverage-${{ github.job }}-${{ matrix.pl_backend }}-Lapack.info - if-no-files-found: error - - cpptestswithOpenBLASNoLAPACK: - if: ${{ !contains(fromJSON('["schedule", "workflow_dispatch"]'), github.event_name) }} - strategy: - matrix: - os: [ubuntu-22.04] - pl_backend: ["lightning_qubit"] - timeout-minutes: 60 - name: C++ tests (OpenBLAS without LAPACK) - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/setup-python@v4 - name: Install Python - with: - python-version: '3.9' - - - name: Checkout PennyLane-Lightning - uses: actions/checkout@v3 - - - name: Install dependencies - run: sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION liblapack-dev libopenblas-dev ninja-build gcovr lcov - - - name: Build and run unit tests - run: | - cmake . -BBuild -G Ninja \ - -DCMAKE_BUILD_TYPE=Debug \ - -DENABLE_PYTHON=OFF \ - -DPL_BACKEND=${{ matrix.pl_backend }} \ - -DBUILD_TESTS=ON \ - -DENABLE_LAPACK=OFF \ - -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION) \ - -DENABLE_COVERAGE=ON \ - -DLQ_ENABLE_KERNEL_OMP=ON - cmake --build ./Build - cd ./Build - mkdir -p ./tests/results - for file in *runner ; do ./$file --order lex --reporter junit --out ./tests/results/report_$file.xml; done; - lcov --directory . -b ../pennylane_lightning/core/src --capture --output-file coverage.info - lcov --remove coverage.info '/usr/*' --output-file coverage.info mv coverage.info coverage-${{ github.job }}-${{ matrix.pl_backend }}.info - name: Upload test results @@ -348,7 +296,9 @@ jobs: python-version: '3.9' - name: Install dependencies - run: sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION libopenblas-dev + run: | + sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION libopenblas-dev + python -m pip install scipy - name: Get required Python packages run: | @@ -386,6 +336,7 @@ jobs: - name: Install backend device run: | cd main + python -m pip install scipy CMAKE_ARGS="-DPL_BACKEND=${{ matrix.pl_backend }} -DENABLE_BLAS=ON -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ python -m pip install -e . -vv @@ -449,14 +400,15 @@ jobs: cp -rf ${{ github.workspace}}/Kokkos_install/${{ matrix.exec_model }}/* Kokkos/ - name: Install dependencies - run: sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION liblapack-dev ninja-build gcovr lcov + run: | + sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION ninja-build gcovr lcov + python -m pip install scipy - name: Build and run unit tests run: | cmake . -BBuild -G Ninja \ -DCMAKE_BUILD_TYPE=Debug \ -DBUILD_TESTS=ON \ - -DENABLE_LAPACK=ON \ -DENABLE_PYTHON=OFF \ -DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos \ -DPL_BACKEND=${{ matrix.pl_backend }} \ @@ -544,7 +496,9 @@ jobs: pwd - name: Install dependencies - run: sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION + run: | + sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION + python -m pip install scipy - name: Get required Python packages run: | @@ -583,6 +537,7 @@ jobs: if: ${{ matrix.pl_backend != 'all'}} run: | cd main + python -m pip install scipy SKIP_COMPILATION=True PL_BACKEND="lightning_qubit" pip install -e . -vv CMAKE_ARGS="-DPL_BACKEND=${{ matrix.pl_backend }} -DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos -DENABLE_PYTHON=ON -DCMAKE_CXX_COMPILER=$(which g++-$GCC_VERSION)" \ python -m pip install -e . -vv @@ -658,7 +613,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} upload-to-codecov-linux-cpp: - needs: [cpptests, cpptestswithOpenBLAS, cpptestswithOpenBLASNoLAPACK, cpptestswithKokkos] + needs: [cpptests, cpptestswithOpenBLAS, cpptestswithKokkos] name: Upload cpp coverage data to codecov runs-on: ubuntu-latest steps: @@ -713,7 +668,9 @@ jobs: cp -rf ${{ github.workspace}}/Kokkos_install/${{ matrix.exec_model }}/* Kokkos/ - name: Install dependencies - run: sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION liblapack-dev ninja-build gcovr lcov + run: | + sudo apt-get update && sudo apt-get -y -q install cmake gcc-$GCC_VERSION g++-$GCC_VERSION ninja-build gcovr lcov + python -m pip install scipy - name: Build and run unit tests run: | @@ -721,7 +678,6 @@ jobs: cmake . -BBuild -G Ninja \ -DCMAKE_BUILD_TYPE=Debug \ -DBUILD_TESTS=ON \ - -DENABLE_LAPACK=ON \ -DENABLE_PYTHON=OFF \ -DCMAKE_PREFIX_PATH=${{ github.workspace }}/Kokkos \ -DPL_BACKEND="lightning_qubit;lightning_kokkos" \ diff --git a/.github/workflows/tests_linux_x86_mpi_gpu.yml b/.github/workflows/tests_linux_x86_mpi_gpu.yml index b491363bfc..7d73a98b0b 100644 --- a/.github/workflows/tests_linux_x86_mpi_gpu.yml +++ b/.github/workflows/tests_linux_x86_mpi_gpu.yml @@ -14,7 +14,7 @@ on: push: branches: - main - pull_request: + #pull_request: env: COVERAGE_FLAGS: "--cov=pennylane_lightning --cov-report=term-missing --cov-report=xml:./coverage.xml --no-flaky-report -p no:warnings --tb=native" @@ -54,11 +54,6 @@ jobs: run: | git fetch tags --force git checkout $(git tag | sort -V | tail -1) - - uses: actions/setup-python@v4 - id: setup_python - name: Install Python - with: - python-version: '3.9' # Since the self-hosted runner can be re-used. It is best to set up all package # installations in a virtual environment that gets cleaned at the end of each workflow run @@ -96,8 +91,7 @@ jobs: python -m pip install -r requirements-dev.txt # Omitting the installation of cmake v3.29.0 due to # https://github.com/scikit-build/cmake-python-distributions/pull/474 - python -m pip install "cmake!=3.29.0" custatevec-cu12 - sudo apt-get -y -q install liblapack-dev + python -m pip install "cmake!=3.29.0" custatevec-cu12 scipy - name: Validate GPU version and installed compiler and modules run: | @@ -122,11 +116,11 @@ jobs: export CUQUANTUM_SDK=$(python -c "import site; print( f'{site.getsitepackages()[0]}/cuquantum/lib')") cmake . -BBuild \ -DPL_BACKEND=lightning_gpu \ + -DENABLE_PYTHON=OFF \ -DENABLE_MPI=ON \ -DCMAKE_BUILD_TYPE=Debug \ -DENABLE_COVERAGE=ON \ -DBUILD_TESTS=ON \ - -DENABLE_LAPACK=ON \ -DCMAKE_CXX_COMPILER=mpicxx \ -DCMAKE_CUDA_COMPILER=$(which nvcc) \ -DCMAKE_CUDA_ARCHITECTURES="86" \ @@ -198,13 +192,6 @@ jobs: git fetch --tags --force git checkout $(git tag | sort -V | tail -1) - - - uses: actions/setup-python@v4 - id: setup_python - name: Install Python - with: - python-version: '3.9' - # Since the self-hosted runner can be re-used. It is best to set up all package # installations in a virtual environment that gets cleaned at the end of each workflow run - name: Setup Python virtual environment @@ -226,6 +213,8 @@ jobs: source ${{ env.VENV_NAME }}/bin/activate echo "venv_name=${{ env.VENV_NAME }}" >> $GITHUB_OUTPUT + python -m pip install scipy + - name: Display Python-Path id: python_path run: | diff --git a/.github/workflows/tests_windows.yml b/.github/workflows/tests_windows.yml index 395d4a8bdd..66bcce17ed 100644 --- a/.github/workflows/tests_windows.yml +++ b/.github/workflows/tests_windows.yml @@ -93,44 +93,7 @@ jobs: cmake --build ./Build --config Debug --verbose cmake --install ./Build --config Debug --verbose - build_dependencies_vcpkg: - strategy: - fail-fast: false - matrix: - os: [windows-latest] - timeout-minutes: 30 - name: vcpkg dependencies - runs-on: ${{ matrix.os }} - - steps: - - name: Cache installation directories - id: vcpkg-cache - uses: actions/cache@v4 - with: - path: D:\a\install_dir\vcpkg - key: ${{ matrix.os }}-vcpkg - - - name: Clone vcpkg - if: steps.vcpkg-cache.outputs.cache-hit != 'true' - run: | - mkdir -p D:\a\install_dir - cd D:\a\install_dir\ - git clone --quiet --recursive https://github.com/microsoft/vcpkg.git - - - name: Install dependencies - if: steps.vcpkg-cache.outputs.cache-hit != 'true' - run: | - python -m pip install cmake build ninja - - - name: Build Lapack library - if: steps.vcpkg-cache.outputs.cache-hit != 'true' - run: | - cd D:\a\install_dir\vcpkg - .\bootstrap-vcpkg.bat - vcpkg install lapack - cpptests: - needs: [build_dependencies_vcpkg] if: ${{ !contains(fromJSON('["schedule", "workflow_dispatch"]'), github.event_name) }} timeout-minutes: 30 name: C++ tests (Windows) @@ -140,15 +103,17 @@ jobs: os: [windows-latest] pl_backend: ["lightning_qubit"] steps: + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: '3.9' + - name: Checkout PennyLane-Lightning uses: actions/checkout@v3 - - - name: Restoring cached vcpkg - id: vcpkg-cache - uses: actions/cache@v4 - with: - path: D:\a\install_dir\vcpkg - key: ${{ matrix.os }}-vcpkg + + - name: Install dependencies + run: | + python -m pip install cmake build ninja scipy - name: Setup OpenCppCoverage and add to PATH run: | @@ -163,8 +128,6 @@ jobs: -DENABLE_PYTHON=OFF ` -DENABLE_GATE_DISPATCHER=OFF ` -DPL_BACKEND=${{ matrix.pl_backend }} ` - -DENABLE_LAPACK=ON ` - -DCMAKE_TOOLCHAIN_FILE=D:\a\install_dir\vcpkg\scripts\buildsystems\vcpkg.cmake ` -DENABLE_WARNINGS=OFF cmake --build .\Build --config RelWithDebInfo mkdir -p .\Build\tests\results @@ -197,7 +160,7 @@ jobs: cpptestswithkokkos: if: ${{ !contains(fromJSON('["schedule", "workflow_dispatch"]'), github.event_name) }} - needs: [build_dependencies_kokkos, build_dependencies_vcpkg, win-set-matrix-x86] + needs: [build_dependencies_kokkos, win-set-matrix-x86] strategy: matrix: os: [windows-latest] @@ -210,6 +173,11 @@ jobs: runs-on: ${{ matrix.os }} steps: + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: '3.9' + - name: Restoring cached Kokkos id: kokkos-cache uses: actions/cache@v4 @@ -217,13 +185,10 @@ jobs: path: D:\a\install_dir\${{ matrix.exec_model }} key: ${{ matrix.os }}-kokkos${{ matrix.kokkos_version }}-${{ matrix.exec_model }}-Debug - - name: Restoring cached vcpkg - id: vcpkg-cache - uses: actions/cache@v4 - with: - path: D:\a\install_dir\vcpkg - key: ${{ matrix.os }}-vcpkg - + - name: Install dependencies + run: | + python -m pip install cmake build ninja scipy + - name: Checkout PennyLane-Lightning uses: actions/checkout@v3 @@ -251,10 +216,8 @@ jobs: -DENABLE_PYTHON=OFF ` -DENABLE_GATE_DISPATCHER=OFF ` -DCMAKE_PREFIX_PATH=D:\a\pennylane-lightning\pennylane-lightning\Kokkos ` - -DCMAKE_TOOLCHAIN_FILE=D:\a\install_dir\vcpkg\scripts\buildsystems\vcpkg.cmake ` -DENABLE_OPENMP=OFF ` -DPL_BACKEND=${{ matrix.pl_backend }} ` - -DENABLE_LAPACK=ON ` -DENABLE_WARNINGS=OFF -T clangcl cmake --build .\Build --config Debug -- /p:UseMultiToolTask=true /p:EnforceProcessCountAcrossBuilds=true /p:MultiProcMaxCount=2 mkdir -p .\Build\tests\results diff --git a/.github/workflows/tests_without_binary.yml b/.github/workflows/tests_without_binary.yml index e01964ce2b..9af0aa9707 100644 --- a/.github/workflows/tests_without_binary.yml +++ b/.github/workflows/tests_without_binary.yml @@ -10,7 +10,7 @@ on: type: string required: true description: The version of PennyLane to use. Valid values are either 'release' (most recent release candidate), 'stable' (most recent git-tag) or 'latest' (most recent commit from master) - pull_request: + #pull_request: push: branches: - master diff --git a/.github/workflows/wheel_linux_aarch64.yml b/.github/workflows/wheel_linux_aarch64.yml index 1a10b46a30..5ac0900107 100644 --- a/.github/workflows/wheel_linux_aarch64.yml +++ b/.github/workflows/wheel_linux_aarch64.yml @@ -130,7 +130,7 @@ jobs: # Python build settings CIBW_BEFORE_BUILD: | cat /etc/yum.conf | sed "s/\[main\]/\[main\]\ntimeout=5/g" > /etc/yum.conf - python -m pip install ninja cmake~=3.24.0 + python -m pip install ninja cmake~=3.24.0 scipy CIBW_ENVIRONMENT: | PL_BACKEND="${{ matrix.pl_backend }}" diff --git a/.github/workflows/wheel_linux_ppc64le.yml b/.github/workflows/wheel_linux_ppc64le.yml index 3d94bf906e..ab422001e8 100644 --- a/.github/workflows/wheel_linux_ppc64le.yml +++ b/.github/workflows/wheel_linux_ppc64le.yml @@ -129,7 +129,7 @@ jobs: # Python build settings CIBW_BEFORE_BUILD: | cat /etc/yum.conf | sed "s/\[main\]/\[main\]\ntimeout=5/g" > /etc/yum.conf - python -m pip install ninja cmake~=3.24.0 + python -m pip install ninja cmake~=3.24.0 scipy CIBW_ENVIRONMENT: | PL_BACKEND="${{ matrix.pl_backend }}" diff --git a/.github/workflows/wheel_linux_x86_64.yml b/.github/workflows/wheel_linux_x86_64.yml index 9101665494..888ae4a5fa 100644 --- a/.github/workflows/wheel_linux_x86_64.yml +++ b/.github/workflows/wheel_linux_x86_64.yml @@ -140,7 +140,7 @@ jobs: # Python build settings CIBW_BEFORE_BUILD: | cat /etc/yum.conf | sed "s/\[main\]/\[main\]\ntimeout=5/g" > /etc/yum.conf - python -m pip install ninja cmake~=3.24.0 + python -m pip install ninja cmake~=3.24.0 scipy yum clean all -y yum install centos-release-scl-rh -y yum install devtoolset-11-gcc-c++ -y diff --git a/.github/workflows/wheel_linux_x86_64_cuda.yml b/.github/workflows/wheel_linux_x86_64_cuda.yml index f537e53b31..f92916842e 100644 --- a/.github/workflows/wheel_linux_x86_64_cuda.yml +++ b/.github/workflows/wheel_linux_x86_64_cuda.yml @@ -71,7 +71,7 @@ jobs: # Python build settings CIBW_BEFORE_BUILD: | cat /etc/yum.conf | sed "s/\[main\]/\[main\]\ntimeout=5/g" > /etc/yum.conf - python -m pip install ninja cmake~=3.24.3 auditwheel~=5.0 custatevec-cu${{ matrix.cuda_version }} + python -m pip install ninja cmake~=3.24.3 auditwheel~=5.0 custatevec-cu${{ matrix.cuda_version }} scipy yum clean all -y yum install centos-release-scl-rh -y yum install devtoolset-11-gcc-c++ -y diff --git a/.github/workflows/wheel_macos_arm64.yml b/.github/workflows/wheel_macos_arm64.yml index 1d5e9f097a..1872c25d76 100644 --- a/.github/workflows/wheel_macos_arm64.yml +++ b/.github/workflows/wheel_macos_arm64.yml @@ -84,7 +84,7 @@ jobs: # Python build settings CIBW_BEFORE_BUILD: | - python -m pip install pybind11 ninja cmake~=3.24.0 setuptools + python -m pip install pybind11 ninja cmake~=3.24.0 setuptools scipy CIBW_ENVIRONMENT: | CMAKE_ARGS="-DCMAKE_CXX_COMPILER_TARGET=arm64-apple-macos11 -DCMAKE_SYSTEM_NAME=Darwin -DCMAKE_SYSTEM_PROCESSOR=ARM64 -DENABLE_OPENMP=OFF" \ diff --git a/.github/workflows/wheel_macos_x86_64.yml b/.github/workflows/wheel_macos_x86_64.yml index e3931dbcff..9144962d39 100644 --- a/.github/workflows/wheel_macos_x86_64.yml +++ b/.github/workflows/wheel_macos_x86_64.yml @@ -136,7 +136,7 @@ jobs: # Python build settings CIBW_BEFORE_BUILD: | - python -m pip install pybind11 ninja cmake~=3.24.0 setuptools + python -m pip install pybind11 ninja cmake~=3.24.0 setuptools scipy PL_BACKEND: ${{ matrix.pl_backend }} diff --git a/.github/workflows/wheel_win_x86_64.yml b/.github/workflows/wheel_win_x86_64.yml index 3d7e86f0e5..b827a2ab78 100644 --- a/.github/workflows/wheel_win_x86_64.yml +++ b/.github/workflows/wheel_win_x86_64.yml @@ -85,7 +85,7 @@ jobs: cmake --install ./Build --config RelWithDebInfo --verbose win-wheels: - needs: [set_wheel_build_matrix, build_dependencies] + needs: [set_wheel_build_matrix] strategy: fail-fast: false matrix: @@ -127,7 +127,8 @@ jobs: # Python build settings CIBW_BEFORE_BUILD: | - python -m pip install pybind11 cmake~=3.24.0 build + python -m pip install pybind11 cmake~=3.24.0 + python -m pip install -r requirements.txt #Temporarily commenting while solving problems to find binaries in CIBW tests. # CIBW_BEFORE_TEST: | @@ -140,7 +141,7 @@ jobs: CIBW_BUILD_VERBOSITY: 3 - CIBW_BUILD_FRONTEND: build + #CIBW_BUILD_FRONTEND: build run: python -m cibuildwheel --output-dir wheelhouse diff --git a/CMakeLists.txt b/CMakeLists.txt index efbe99be3b..098875e6bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,6 @@ option(ENABLE_COVERAGE "Enable code coverage" OFF) option(ENABLE_WARNINGS "Enable warnings" ON) option(ENABLE_NATIVE "Enable native CPU build tuning" OFF) option(ENABLE_PYTHON "Enable compilation of the Python module" ON) -option(ENABLE_LAPACK "Enable compilation of LAPACK" OFF) # OpenMP find_package(OpenMP) @@ -82,8 +81,34 @@ set(CMAKE_POLICY_DEFAULT_CMP0127 NEW) # To suppress pybind11 CMP0127 warning # Add pybind11 include(FetchContent) +find_package(Python COMPONENTS Interpreter Development) + +message("Python site-packages directory: ${Python_SITELIB}") + +if (CMAKE_SYSTEM_NAME MATCHES "Windows" OR CMAKE_SYSTEM_NAME MATCHES "Linux") + if(IS_DIRECTORY ${SCIPY_LIBS_DIR}) + set(SCIPYLIBS ${SCIPY_LIBS_DIR}/scipy.libs) + else() + set(SCIPYLIBS ${Python_SITELIB}/scipy.libs) + endif() + + ##TODO add windows support + if (CMAKE_SYSTEM_NAME MATCHES "Windows") + string(REPLACE "\\" "/" SCIPYLIBS "${SCIPYLIBS}") + endif() + + if(IS_DIRECTORY ${SCIPYLIBS}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pennylane_lightning/core/src/utils/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/pennylane_lightning/core/src/utils/config.h) + elseif() + message(FATAL_ERROR "scipy.libs not found.") + endif() +else() + set(SCIPYLIBS "/System/Library/Frameworks/Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/libLAPACK.dylib") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pennylane_lightning/core/src/utils/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/pennylane_lightning/core/src/utils/config.h) +endif() + + if(ENABLE_PYTHON) - find_package(Python COMPONENTS Interpreter Development) FetchContent_Declare(pybind11 GIT_REPOSITORY https://github.com/pybind/pybind11.git GIT_TAG v2.11.1 diff --git a/README.rst b/README.rst index 74090c8266..63980f2b8f 100644 --- a/README.rst +++ b/README.rst @@ -389,26 +389,6 @@ where ``${TARGET}`` is one of the following .. docker-end-inclusion-marker-do-not-remove -LAPACK support -************** - -LAPACK, a numerical linear algebra library, is required to enable stochastic measurement support in the C++ backend. We suggest first installing ``LAPACK`` following instructions in `LAPACK document `_. - -On Debian-based Linux systems, LAPACK can be also installed via ``apt``: - -.. code-block:: console - - $ sudo apt -y update && - $ sudo apt install liblapack-dev - -where LAPACK is included in ``liblapack-dev``. - -On Windows systems, LAPACK is recommended to be built and installed using `vcpkg `_ following the instructions `here `_. - -The CMake option ``-DENABLE_LAPACK=ON`` must also be specified when building C++ backends. For Windows systems, we suggest adding the CMake option ``-DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake`` to ensure ``LAPACK`` can be found with CMake. - -On MacOS systems, the Accelerate framework already includes optimized implementations of the LAPACK library. - Contributing ************ @@ -475,6 +455,5 @@ PennyLane Lightning makes use of the following libraries and tools, which are un - **pybind11:** https://github.com/pybind/pybind11 - **Kokkos Core:** https://github.com/kokkos/kokkos - **NVIDIA cuQuantum:** https://developer.nvidia.com/cuquantum-sdk -- **LAPACK:** https://github.com/Reference-LAPACK/lapack .. acknowledgements-end-inclusion-marker-do-not-remove diff --git a/cmake/process_options.cmake b/cmake/process_options.cmake index 14809c3597..7feb24b495 100644 --- a/cmake/process_options.cmake +++ b/cmake/process_options.cmake @@ -101,19 +101,3 @@ if (UNIX AND (${CMAKE_SYSTEM_PROCESSOR} MATCHES "(AMD64)|(X64)|(x64)|(x86_64)")) target_compile_options(lightning_compile_options INTERFACE -mavx) endif() - -if(ENABLE_LAPACK) - find_package(LAPACK REQUIRED) - if(LAPACK_FOUND) - message(STATUS "LAPACK found.") - target_link_libraries(lightning_external_libs INTERFACE LAPACK::LAPACK) - target_compile_options(lightning_compile_options INTERFACE "-DPL_USE_LAPACK=1") - else() - if(MSVC) - if(NOT CMAKE_TOOLCHAIN_FILE) - message(FATAL_ERROR "LAPACK is enabled but not found. Please make sure you set CMAKE_TOOLCHAIN_FILE to use the vcpkg toolchain (/scripts/buildsystems/vcpkg.cmake) after vcpkg install LAPACK.\n") - endif() - endif() - message(FATAL_ERROR "LAPACK is enabled but not found.\n") - endif() -endif() diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 58da0aa862..19067082da 100644 --- a/pennylane_lightning/core/_version.py +++ b/pennylane_lightning/core/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.36.0-dev20" +__version__ = "0.36.0-dev21" diff --git a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp index a5f20a3848..fa1a9bcc14 100644 --- a/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp +++ b/pennylane_lightning/core/src/measurements/tests/Test_MeasurementsBase.cpp @@ -570,7 +570,7 @@ TEST_CASE("Expval Shot- NamedObs", "[MeasurementsBase][Observables]") { } } -#ifdef PL_USE_LAPACK +// #ifndef _MSC_VER template void testHermitianObsExpvalShot() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; @@ -673,7 +673,7 @@ TEST_CASE("Expval Shot - HermitianObs ", "[MeasurementsBase][Observables]") { testHermitianObsExpvalShot(); } } -#endif +// #endif template void testHermitianObsExpval() { if constexpr (!std::is_same_v) { @@ -839,7 +839,7 @@ template void testTensorProdObsExpvalShot() { expected, static_cast(0.20))); } -#ifdef PL_USE_LAPACK + // #ifndef _MSC_VER DYNAMIC_SECTION(" With Identity and shots_range" << StateVectorToName::name) { size_t num_shots = 80000; @@ -860,7 +860,7 @@ template void testTensorProdObsExpvalShot() { REQUIRE_THAT(result, Catch::Matchers::WithinRel( expected, static_cast(0.20))); } -#endif + // #endif testTensorProdObsExpvalShot(); } @@ -1011,7 +1011,7 @@ TEST_CASE("Var - HermitianObs", "[MeasurementsBase][Observables]") { } } -#ifdef PL_USE_LAPACK +// #ifndef _MSC_VER template void testHermitianObsShotVar() { if constexpr (!std::is_same_v) { using StateVectorT = typename TypeList::Type; @@ -1096,8 +1096,7 @@ TEST_CASE("Var - HermitianObs Shot", "[MeasurementsBase][Observables]") { testHermitianObsShotVar(); } } - -#endif +// #endif template void testTensorProdObsVarShot() { if constexpr (!std::is_same_v) { @@ -1148,7 +1147,7 @@ template void testTensorProdObsVarShot() { expected, static_cast(0.20))); } -#ifdef PL_USE_LAPACK + // #ifndef _MSC_VER DYNAMIC_SECTION("With Hermitian and NameObs" << StateVectorToName::name) { using MatrixT = std::vector; @@ -1198,7 +1197,7 @@ template void testTensorProdObsVarShot() { REQUIRE_THAT(result, Catch::Matchers::WithinRel( expected, static_cast(0.20))); } -#endif + // #endif DYNAMIC_SECTION(" full wires with apply operations" << StateVectorToName::name) { @@ -1556,8 +1555,7 @@ template void testHamiltonianObsExpvalShot() { REQUIRE_THAT(res, Catch::Matchers::WithinRel( expected, static_cast(0.20))); } - -#ifdef PL_USE_LAPACK + // #ifndef _MSC_VER DYNAMIC_SECTION("YHer" << StateVectorToName::name) { auto Y0 = std::make_shared>( "PauliY", std::vector{0}); @@ -1578,7 +1576,7 @@ template void testHamiltonianObsExpvalShot() { REQUIRE_THAT(res, Catch::Matchers::WithinRel( expected, static_cast(0.20))); } -#endif + // #endif testHamiltonianObsExpvalShot(); } @@ -1638,7 +1636,6 @@ template void testHamiltonianObsVarShot() { expected, static_cast(0.20))); } -#ifdef PL_USE_LAPACK DYNAMIC_SECTION("YHer" << StateVectorToName::name) { using ComplexT = typename StateVectorT::ComplexT; auto Y0 = std::make_shared>( @@ -1667,7 +1664,6 @@ template void testHamiltonianObsVarShot() { REQUIRE_THAT(res, Catch::Matchers::WithinRel( expected, static_cast(0.20))); } -#endif testHamiltonianObsVarShot(); } diff --git a/pennylane_lightning/core/src/observables/Observables.hpp b/pennylane_lightning/core/src/observables/Observables.hpp index 884bc2be6f..41ef728b76 100644 --- a/pennylane_lightning/core/src/observables/Observables.hpp +++ b/pennylane_lightning/core/src/observables/Observables.hpp @@ -23,9 +23,9 @@ #include "Error.hpp" #include "Util.hpp" -#ifdef PL_USE_LAPACK +// #ifndef _MSC_VER #include "UtilLinearAlg.hpp" -#endif +// #endif namespace Pennylane::Observables { /** @@ -220,12 +220,10 @@ class HermitianObsBase : public Observable { MatrixT matrix_; std::vector wires_; -#ifdef PL_USE_LAPACK - - private: + // #ifndef _MSC_VER std::vector eigenVals_; MatrixT unitary_; -#endif + // #endif private: [[nodiscard]] auto isEqual(const Observable &other) const @@ -247,7 +245,7 @@ class HermitianObsBase : public Observable { : matrix_{std::move(matrix)}, wires_{std::move(wires)} { PL_ASSERT(matrix_.size() == Util::exp2(2 * wires_.size())); -#ifdef PL_USE_LAPACK + // #ifndef _MSC_VER std::vector> mat(matrix_.size()); std::transform(matrix_.begin(), matrix_.end(), mat.begin(), @@ -265,7 +263,7 @@ class HermitianObsBase : public Observable { std::transform( unitary.begin(), unitary.end(), unitary_.begin(), [](ComplexT value) { return static_cast(value); }); -#endif + // #endif } [[nodiscard]] auto getMatrix() const -> const MatrixT & { return matrix_; } @@ -286,7 +284,7 @@ class HermitianObsBase : public Observable { [[maybe_unused]] StateVectorT &sv, [[maybe_unused]] std::vector> &eigenValues, [[maybe_unused]] std::vector &ob_wires) const override { -#ifdef PL_USE_LAPACK + // #ifndef _MSC_VER std::vector> mat(matrix_.size()); std::transform(matrix_.begin(), matrix_.end(), mat.begin(), @@ -304,10 +302,11 @@ class HermitianObsBase : public Observable { ob_wires = wires_; sv.applyMatrix(unitary_, wires_); eigenValues.push_back(eigenVals_); -#else - PL_ABORT("Hermitian observables do not support shot measurement. " - "Please link against Lapack."); -#endif + // #else + // PL_ABORT("Hermitian observables do not support shot + // measurement for " + // "Windows."); + // #endif } }; diff --git a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp index 694d0a6b22..099efb754f 100644 --- a/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp +++ b/pennylane_lightning/core/src/observables/tests/Test_Observables.cpp @@ -207,29 +207,28 @@ template void testHermitianObsBase() { REQUIRE(ob2 != ob3); } -#ifdef PL_USE_LAPACK - DYNAMIC_SECTION("Failed to create a HermitianObs- " - << StateVectorToName::name) { - std::mt19937_64 re{1337}; - constexpr size_t num_qubits = 3; - auto init_state = - createRandomStateVectorData(re, num_qubits); - - StateVectorT state_vector(init_state.data(), init_state.size()); - auto obs = - HermitianObsT{std::vector{1.0, 0.0, 1.0, 0.0}, {0}}; - - std::vector> eigenValues; - std::vector ob_wires; - - REQUIRE_THROWS_WITH( - obs.applyInPlaceShots(state_vector, eigenValues, ob_wires), - Catch::Matchers::Contains("The matrix passed to HermitianObs " - "is not a Hermitian matrix.")); - } -#endif - -#ifndef PL_USE_LAPACK + /*#ifndef _MSC_VER + DYNAMIC_SECTION("Failed to create a HermitianObs- " + << StateVectorToName::name) { + std::mt19937_64 re{1337}; + constexpr size_t num_qubits = 3; + auto init_state = + createRandomStateVectorData(re, num_qubits); + + StateVectorT state_vector(init_state.data(), + init_state.size()); auto obs = HermitianObsT{std::vector{1.0, + 0.0, 1.0, 0.0}, {0}}; + + std::vector> eigenValues; + std::vector ob_wires; + + REQUIRE_THROWS_WITH( + obs.applyInPlaceShots(state_vector, eigenValues, + ob_wires), Catch::Matchers::Contains("The matrix passed to HermitianObs + " "is not a Hermitian matrix.")); + } + #else + */ DYNAMIC_SECTION("Failed for HermitianObs for applyInPlaceShots - " << StateVectorToName::name) { std::mt19937_64 re{1337}; @@ -247,9 +246,10 @@ template void testHermitianObsBase() { REQUIRE_THROWS_WITH( obs.applyInPlaceShots(state_vector, eigenValues, ob_wires), Catch::Matchers::Contains( - "Hermitian observables do not support shot measurement.")); + "Hermitian observables do not support shot measurement for " + "Windows.")); } -#endif + // #endif testHermitianObsBase(); } diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp index 2875b22a6d..6b36ccb4c4 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/utils/IntegerInterval.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/utils/IntegerInterval.hpp index 0fdbef6fd7..cc5401d614 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/utils/IntegerInterval.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/utils/IntegerInterval.hpp @@ -43,9 +43,9 @@ template class IntegerInterval { return (min_ <= test_val) && (test_val < max_); } - [[nodiscard]] IntegerType min() const { return min_; } + [[nodiscard]] IntegerType MIN() const { return min_; } - [[nodiscard]] IntegerType max() const { return max_; } + [[nodiscard]] IntegerType MAX() const { return max_; } }; /** @@ -109,7 +109,7 @@ constexpr auto full_domain() -> IntegerInterval { template bool is_disjoint(const IntegerInterval &interval1, const IntegerInterval &interval2) { - return (interval1.max() <= interval2.min()) || - (interval2.max() <= interval1.min()); + return (interval1.MAX() <= interval2.MIN()) || + (interval2.MAX() <= interval1.MIN()); } } // namespace Pennylane::LightningQubit::Util diff --git a/pennylane_lightning/core/src/utils/CMakeLists.txt b/pennylane_lightning/core/src/utils/CMakeLists.txt index ac86df6f5c..55d1095760 100644 --- a/pennylane_lightning/core/src/utils/CMakeLists.txt +++ b/pennylane_lightning/core/src/utils/CMakeLists.txt @@ -4,9 +4,7 @@ project(lightning_utils LANGUAGES CXX) set(LQUBIT_UTILS_FILES RuntimeInfo.cpp CACHE INTERNAL "" FORCE) -if(ENABLE_LAPACK) - list(APPEND LQUBIT_UTILS_FILES UtilLinearAlg.cpp) -endif() +list(APPEND LQUBIT_UTILS_FILES UtilLinearAlg.cpp) add_library(lightning_utils STATIC ${LQUBIT_UTILS_FILES}) @@ -14,6 +12,8 @@ target_include_directories(lightning_utils INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} target_link_libraries(lightning_utils INTERFACE lightning_compile_options lightning_external_libs ) + + set_property(TARGET lightning_utils PROPERTY POSITION_INDEPENDENT_CODE ON) if (BUILD_TESTS) diff --git a/pennylane_lightning/core/src/utils/Memory.hpp b/pennylane_lightning/core/src/utils/Memory.hpp index b9886d5a3d..60e6c58656 100644 --- a/pennylane_lightning/core/src/utils/Memory.hpp +++ b/pennylane_lightning/core/src/utils/Memory.hpp @@ -209,6 +209,9 @@ struct Undefined {}; ///@cond DEV template struct commonAlignmentHelper { + constexpr static size_t required_alignment = + std::alignment_of_v; + constexpr static size_t value = std::max( TypeList::Type::template required_alignment, commonAlignmentHelper::value); diff --git a/pennylane_lightning/core/src/utils/SharedLibLoader.hpp b/pennylane_lightning/core/src/utils/SharedLibLoader.hpp new file mode 100644 index 0000000000..6ca9f7c3b4 --- /dev/null +++ b/pennylane_lightning/core/src/utils/SharedLibLoader.hpp @@ -0,0 +1,94 @@ +// Copyright 2018-2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file + * Dynamic shared library functions API wrapper. + */ +#pragma once +#include + +#if defined(__APPLE__) || defined(__linux__) +#include +// TODO add windows support +#elif defined(_MSC_VER) +#include +#endif + +#include "Error.hpp" + +namespace Pennylane::Util { +/** + * Dynamic shared library loading wrapper class + */ +// Adapted from Catalyst +// (https://github.com/PennyLaneAI/catalyst/blob/f016a31f69d1b8a84bc9612af1bc64f0575506e9/runtime/lib/capi/ExecutionContext.hpp#L75) + +// Ignore invalid warnings for compile-time checks +// NOLINTBEGIN +class SharedLibLoader final { + private: +#if defined(__APPLE__) || defined(__linux__) + void *handle_{nullptr}; +// TODO add windows support +#elif defined(_MSC_VER) + HMODULE handle_{nullptr}; +#endif + + public: + SharedLibLoader(); + explicit SharedLibLoader(const std::string &filename) { +#if defined(__APPLE__) + auto rtld_flags = RTLD_LAZY; +#elif defined(__linux__) + auto rtld_flags = RTLD_LAZY | RTLD_NODELETE; +#endif + +#if defined(__APPLE__) || defined(__linux__) + handle_ = dlopen(filename.c_str(), rtld_flags); + // This allows users to use pre-installed LAPACK package + PL_ABORT_IF(!handle_, dlerror()); +// TODO add windows support +#elif defined(_MSC_VER) + handle_ = LoadLibrary(filename.c_str()); + PL_ABORT_IF(!handle_, std::to_string(GetLastError())); +#endif + } + + ~SharedLibLoader() { +#if defined(__APPLE__) || defined(__linux__) + dlclose(handle_); +// TODO add windows support +#elif defined(_MSC_VER) + FreeLibrary(handle_); +#endif + } + + void *getHandle() { return handle_; } + + void *getSymbol(const std::string &symbol) { +#if defined(__APPLE__) || defined(__linux__) + void *sym = dlsym(handle_, symbol.c_str()); + PL_ABORT_IF(!sym, dlerror()); +// TODO add windows support +#elif defined(_MSC_VER) + void *sym = reinterpret_cast(GetProcAddress(handle_, symbol.c_str())); + //PL_ABORT_IF(!sym, std::to_string(GetLastError())); +#endif + return sym; + } +}; +// NOLINTEND + +} // namespace Pennylane::Util \ No newline at end of file diff --git a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp index 55fcddb187..bba5d7a430 100644 --- a/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp +++ b/pennylane_lightning/core/src/utils/UtilLinearAlg.hpp @@ -21,26 +21,71 @@ #include #include +#include +#include +#include +#include +#include #include +#include + +#if defined(__APPLE__) || defined(__linux__) +#include +// TODO add windows support +#elif defined(_MSC_VER) +#include +#endif + +#include "SharedLibLoader.hpp" + +#include "config.h" + /// @cond DEV namespace { -extern "C" { -// LAPACK routine for complex Hermitian eigensystems -extern void cheev_(const char *jobz, const char *uplo, const int *n, - std::complex *a, const int *lda, float *w, - std::complex *work, const int *lwork, float *rwork, - int *info); -extern void zheev_(const char *jobz, const char *uplo, const int *n, - std::complex *a, const int *lda, double *w, - std::complex *work, const int *lwork, double *rwork, - int *info); -} +// Declare heev function pointers to access corresponding functions in +// LAPACK/OpenBLAS +using zheevPtr = void (*)(const char *, const char *, const int *, + std::complex *, const int *, double *, + std::complex *, const int *, double *, int *); +using cheevPtr = void (*)(const char *, const char *, const int *, + std::complex *, const int *, float *, + std::complex *, const int *, float *, int *); + +// Priority table used to sort openblas and its dependencies +std::unordered_map priority_lib = { + {"stdc", 0}, {"gcc", 1}, {"quadmath", 2}, {"gfortran", 3}, {"openblas", 4}}; } // namespace /// @endcond namespace Pennylane::Util { +// Exclusively for python calls and tested in the python layer +// LCOV_EXCL_START +#ifdef __linux__ +/** + * @brief Get the path to the current shared library object. + * + * @return const char* + */ +inline const char *getPath() { + Dl_info dl_info; + PL_ABORT_IF(dladdr((const void *)getPath, &dl_info) == 0, + "Can't get the path to the shared library."); + return dl_info.dli_fname; +} +// TODO add windows support +#elif defined(_MSC_VER) +inline std::string getPath() { + char buffer[MAX_PATH]; + GetModuleFileName(nullptr, buffer, MAX_PATH); + std::string fullPath(buffer); + std::size_t pos = fullPath.find_last_of("\\/"); + return fullPath.substr(0, pos); +} +#endif +// LCOV_EXCL_STOP + /** * @brief Decompose Hermitian matrix into diagonal matrix and unitaries * @@ -52,6 +97,7 @@ namespace Pennylane::Util { * @param eigenVals eigenvalue results. * @param unitaries unitary result. */ + template void compute_diagonalizing_gates(int n, int lda, const std::vector> &Ah, @@ -69,6 +115,68 @@ void compute_diagonalizing_gates(int n, int lda, ah[j * n + i] = Ah[i * lda + j]; } } +#ifdef __APPLE__ + const std::string libName(SCIPY_LIBS_PATH); + std::shared_ptr blasLib = + std::make_shared(libName); +#else + std::shared_ptr blasLib; + std::vector> blasLibs; + // For C++ usage + std::string scipyPathStr(SCIPY_LIBS_PATH); + + // Exclusively for python calls + // LCOV_EXCL_START + if (!std::filesystem::exists(scipyPathStr)) { + std::string currentPathStr(getPath()); + std::string site_packages_str("site-packages/"); + + std::size_t str_pos = currentPathStr.find(site_packages_str); + if (str_pos != std::string::npos) { + scipyPathStr = + currentPathStr.substr(0, str_pos + site_packages_str.size()); + scipyPathStr += "scipy.libs"; + } + + try { + // convert the relative path to absolute path + scipyPathStr = std::filesystem::canonical(scipyPathStr).string(); + } catch (const std::exception &err) { + std::cout << "Canonical path for scipy.libs" + << " threw exception:\n" + << err.what() << '\n'; + } + } + // LCOV_EXCL_STOP + + std::filesystem::path scipyLibsPath(scipyPathStr); + + std::vector> availableLibs; + + for (const auto &lib : std::filesystem::directory_iterator(scipyLibsPath)) { + if (lib.is_regular_file()) { + for (const auto &iter : priority_lib) { + std::string libname_str = lib.path().filename().string(); + if (libname_str.find(iter.first) != std::string ::npos) { + availableLibs.emplace_back(libname_str, iter.second); + } + } + } + } + + std::sort(availableLibs.begin(), availableLibs.end(), + [](const auto &lhs, const auto &rhs) { + return lhs.second < rhs.second; + }); + + for (const auto &lib : availableLibs) { + auto libPath = scipyLibsPath / lib.first.c_str(); + const std::string libPathStr = libPath.string(); + blasLibs.emplace_back(std::make_shared(libPathStr)); + } + + blasLib = blasLibs.back(); +#endif char jobz = 'V'; // Enable both eigenvalues and eigenvectors computation char uplo = 'L'; // Upper triangle of matrix is stored @@ -78,25 +186,29 @@ void compute_diagonalizing_gates(int n, int lda, int info; if constexpr (std::is_same::value) { + cheevPtr cheev = + reinterpret_cast(blasLib->getSymbol("cheev_")); // Query optimal workspace size - cheev_(&jobz, &uplo, &n, ah.data(), &lda, eigenVals.data(), - work_query.data(), &lwork, rwork.data(), &info); + cheev(&jobz, &uplo, &n, ah.data(), &lda, eigenVals.data(), + work_query.data(), &lwork, rwork.data(), &info); // Allocate workspace lwork = static_cast(work_query[0].real()); std::vector> work_optimal(lwork, {0, 0}); // Perform eigenvalue and eigenvector computation - cheev_(&jobz, &uplo, &n, ah.data(), &lda, eigenVals.data(), - work_optimal.data(), &lwork, rwork.data(), &info); + cheev(&jobz, &uplo, &n, ah.data(), &lda, eigenVals.data(), + work_optimal.data(), &lwork, rwork.data(), &info); } else { + zheevPtr zheev = + reinterpret_cast(blasLib->getSymbol("zheev_")); // Query optimal workspace size - zheev_(&jobz, &uplo, &n, ah.data(), &lda, eigenVals.data(), - work_query.data(), &lwork, rwork.data(), &info); + zheev(&jobz, &uplo, &n, ah.data(), &lda, eigenVals.data(), + work_query.data(), &lwork, rwork.data(), &info); // Allocate workspace lwork = static_cast(work_query[0].real()); std::vector> work_optimal(lwork, {0, 0}); // Perform eigenvalue and eigenvector computation - zheev_(&jobz, &uplo, &n, ah.data(), &lda, eigenVals.data(), - work_optimal.data(), &lwork, rwork.data(), &info); + zheev(&jobz, &uplo, &n, ah.data(), &lda, eigenVals.data(), + work_optimal.data(), &lwork, rwork.data(), &info); } std::transform(ah.begin(), ah.end(), unitary.begin(), diff --git a/pennylane_lightning/core/src/utils/config.h b/pennylane_lightning/core/src/utils/config.h new file mode 100644 index 0000000000..31acc1ca39 --- /dev/null +++ b/pennylane_lightning/core/src/utils/config.h @@ -0,0 +1,23 @@ +// Copyright 2018-2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file + * Record the path to scipy.libs at compile time. + */ + +#ifndef CONFIG_H +#define CONFIG_H +#define SCIPY_LIBS_PATH "" +#endif diff --git a/pennylane_lightning/core/src/utils/config.h.in b/pennylane_lightning/core/src/utils/config.h.in new file mode 100644 index 0000000000..5d4938ead5 --- /dev/null +++ b/pennylane_lightning/core/src/utils/config.h.in @@ -0,0 +1,24 @@ +// Copyright 2018-2024 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file + * Config file for the path to scipy.libs at compile time. + */ + + +#ifndef CONFIG_H +#define CONFIG_H +#define SCIPY_LIBS_PATH "${SCIPYLIBS}" +#endif \ No newline at end of file diff --git a/pennylane_lightning/core/src/utils/tests/CMakeLists.txt b/pennylane_lightning/core/src/utils/tests/CMakeLists.txt index ccb0c8d062..92ca95d66b 100644 --- a/pennylane_lightning/core/src/utils/tests/CMakeLists.txt +++ b/pennylane_lightning/core/src/utils/tests/CMakeLists.txt @@ -32,11 +32,12 @@ set(TEST_SOURCES Test_BitUtil.cpp Test_RuntimeInfo.cpp Test_TypeTraits.cpp Test_Util.cpp + Test_UtilLinearAlg.cpp ) -if(ENABLE_LAPACK) - list(APPEND TEST_SOURCES Test_UtilLinearAlg.cpp) -endif() +#if(NOT WIN32) +# list(APPEND TEST_SOURCES Test_UtilLinearAlg.cpp) +#endif() add_executable(utils_test_runner ${TEST_SOURCES}) target_link_libraries(utils_test_runner PRIVATE utils_tests) diff --git a/requirements-dev.txt b/requirements-dev.txt index 474ef50d1f..31501c907a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -17,3 +17,4 @@ click==8.0.4 cmake==3.28.4 custatevec-cu12 pylint +scipy diff --git a/requirements.txt b/requirements.txt index c888135fa8..ee821aafd0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ pennylane>=0.34 pybind11 pytest~=8.0.0 pytest-cov -pytest-mock \ No newline at end of file +pytest-mock +scipy \ No newline at end of file diff --git a/setup.py b/setup.py index 977f753559..c322769fb4 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ import subprocess import shutil import sys +import site from pathlib import Path from setuptools import setup, Extension, find_namespace_packages from setuptools.command.build_ext import build_ext @@ -58,7 +59,6 @@ def get_backend(): raise ValueError(f"Invalid backend {backend}.") return backend - backend = get_backend() device_name = backend.replace("_", ".") @@ -109,6 +109,8 @@ def build_extension(self, ext: CMakeExtension): else [f"-DPython_EXECUTABLE={sys.executable}"] ) + configure_args += [f"-DSCIPY_LIBS_DIR={site.getsitepackages()[0]}"] + if platform.system() == "Windows": # As Ninja does not support long path for windows yet: # (https://github.com/ninja-build/ninja/pull/2056)