diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 6a9b55cf8f..484cf2ae29 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -23,6 +23,9 @@ ### Breaking changes +* Deprecate PI gates implementation. + [(#925)](https://github.com/PennyLaneAI/pennylane-lightning/pull/925) + * Update MacOS wheel builds to require Monterey (12.0) or greater for x86_64 and ARM. [(#901)](https://github.com/PennyLaneAI/pennylane-lightning/pull/901) diff --git a/doc/benchmark.rst b/doc/benchmark.rst index 132862c38c..92384c67dd 100644 --- a/doc/benchmark.rst +++ b/doc/benchmark.rst @@ -30,9 +30,6 @@ One can also choose a specific datatype by providing an option: $ ./benchmarks/plot_gate_benchmark.py --precision float ./bench_result.json # Results for std::complex $ ./benchmarks/plot_gate_benchmark.py --precision double ./bench_result.json # Results for std::complex - -Currently, we have two different kernels in ``Lightning Qubit`` named ``PI`` and ``LM``. For difference between two kernels, see the documents :cpp:class:`Pennylane::Gates::GateImplementationsPI` and :cpp:class:`Pennylane::Gates::GateImplementationsLM`. - Here are some example plots: .. image:: ./_static/benchmark/PauliX.png diff --git a/doc/lightning_qubit/development/add_gate_kernel.rst b/doc/lightning_qubit/development/add_gate_kernel.rst index fb600454d1..09f9177bf6 100644 --- a/doc/lightning_qubit/development/add_gate_kernel.rst +++ b/doc/lightning_qubit/development/add_gate_kernel.rst @@ -40,7 +40,7 @@ This can be done by modifying two files: // file: gates/KernelType.hpp namespace Pennylane { - enum class KernelType { PI, LM, MyKernel /* This is added */, None }; + enum class KernelType { LM, MyKernel /* This is added */, None }; /* Rest of the file */ @@ -53,7 +53,6 @@ and // file: gates/AvailableKernels.hpp namespace Pennylane { using AvailableKernels = Util::TypeList; } // namespace Pennylane @@ -111,7 +110,6 @@ To test your own kernel implementations, you can go to ``tests/TestKernels.hpp`` .. code-block:: cpp using TestKernels = Pennylane::Util::TypeList; It will automatically test your gate implementation. diff --git a/doc/lightning_qubit/development/avx_kernels/build_system.rst b/doc/lightning_qubit/development/avx_kernels/build_system.rst index 575d9c9795..a630e33471 100644 --- a/doc/lightning_qubit/development/avx_kernels/build_system.rst +++ b/doc/lightning_qubit/development/avx_kernels/build_system.rst @@ -8,11 +8,10 @@ when the library is loaded, and it is used at runtime when it is the most suitab To support AVX2 and AVX512 kernels, we always compile those kernels if the target system is UNIX on x86-64. Specifically, we made separate C++ files for AVX2 and AVX512 kernels and build them as a static library with the corresponding compile options. This is handled by CMake. One can check ``gates/CMakeLists.txt`` file for details. -One caveat is that we want to make sure that default kernels (``KernelType::PI`` and ``KernelType::LM``) are only instantiated once with specific compiler flags during the compile process. +One caveat is that we want to ensure that default ``KernelType::LM`` kernels are only instantiated once with specific compiler flags during the compile process. This is important as the linker sometimes cannot choose the right instantiation when there are multiple instantiations of the same template class. This problem does not arise when all instantiations are compiled with the same options, but with the AVX2/512 kernels, we use different compile options for each translation unit. We solve this problem by adding explicit instantiation declarations in the header files for these kernels -(:ref:`file_pennylane_lightning_core_src_simulators_lightning_qubit_gates_cpu_kernels_GateImplementationsLM.hpp` and -:ref:`file_pennylane_lightning_core_src_simulators_lightning_qubit_gates_cpu_kernels_GateImplementationsPI.hpp`) +(:ref:`file_pennylane_lightning_core_src_simulators_lightning_qubit_gates_cpu_kernels_GateImplementationsLM.hpp`) and compile them as a separate static library. With this, the AVX2/512 kernels are always included in the binary when compiled for UNIX-compatible OSs on x86-64 architecture. diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 05a5ab3841..cb8540718b 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.39.0-dev34" +__version__ = "0.39.0-dev35" diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/CMakeLists.txt b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/CMakeLists.txt index 7c68241a33..bdf0a55528 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/CMakeLists.txt +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/CMakeLists.txt @@ -31,7 +31,7 @@ if (ENABLE_GATE_DISPATCHER AND UNIX AND (${CMAKE_SYSTEM_PROCESSOR} MATCHES "(AMD target_include_directories(lq_gates_register_kernels_avx512 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) set_target_properties(lq_gates_register_kernels_avx512 PROPERTIES POSITION_INDEPENDENT_CODE ON) - add_library(lq_gates_register_kernels_x64 STATIC RegisterKernels_x64.cpp cpu_kernels/GateImplementationsLM.cpp cpu_kernels/GateImplementationsPI.cpp GateIndices.cpp) + add_library(lq_gates_register_kernels_x64 STATIC RegisterKernels_x64.cpp cpu_kernels/GateImplementationsLM.cpp GateIndices.cpp) target_link_libraries(lq_gates_register_kernels_x64 PRIVATE lightning_external_libs lightning_compile_options lightning_gates lightning_utils lightning_qubit_utils) target_include_directories(lq_gates_register_kernels_x64 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) set_target_properties(lq_gates_register_kernels_x64 PROPERTIES POSITION_INDEPENDENT_CODE ON) @@ -53,7 +53,7 @@ else() lightning_gates) set_target_properties(lq_gates_kernel_map PROPERTIES POSITION_INDEPENDENT_CODE ON) - add_library(lq_gates_register_kernels_default STATIC RegisterKernels_Default.cpp cpu_kernels/GateImplementationsLM.cpp cpu_kernels/GateImplementationsPI.cpp GateIndices.cpp) + add_library(lq_gates_register_kernels_default STATIC RegisterKernels_Default.cpp cpu_kernels/GateImplementationsLM.cpp GateIndices.cpp) target_include_directories(lq_gates_register_kernels_default PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(lq_gates_register_kernels_default PRIVATE lightning_gates lightning_external_libs diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/KernelMap.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/KernelMap.hpp index ff2becab8f..e920f72263 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/KernelMap.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/KernelMap.hpp @@ -241,12 +241,10 @@ class OperationKernelMap { OperationKernelMap() : allowed_kernels_{ // LCOV_EXCL_START - {CPUMemoryModel::Unaligned, {KernelType::LM, KernelType::PI}}, - {CPUMemoryModel::Aligned256, - {KernelType::LM, KernelType::PI, KernelType::AVX2}}, + {CPUMemoryModel::Unaligned, {KernelType::LM}}, + {CPUMemoryModel::Aligned256, {KernelType::LM, KernelType::AVX2}}, {CPUMemoryModel::Aligned512, - {KernelType::LM, KernelType::PI, KernelType::AVX2, - KernelType::AVX512}}, + {KernelType::LM, KernelType::AVX2, KernelType::AVX512}}, // LCOV_EXCL_STOP } {} diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/KernelType.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/KernelType.hpp index 006fbae70b..250df09c0c 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/KernelType.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/KernelType.hpp @@ -23,5 +23,5 @@ namespace Pennylane::Gates { /** * @brief Define kernel id for each implementation. */ -enum class KernelType { PI, LM, AVX2, AVX512, None }; +enum class KernelType { LM, AVX2, AVX512, None }; } // namespace Pennylane::Gates diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/RegisterKernels_Default.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/RegisterKernels_Default.cpp index 3c41369415..2f1e5c7613 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/RegisterKernels_Default.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/RegisterKernels_Default.cpp @@ -18,18 +18,15 @@ #include "DynamicDispatcher.hpp" #include "RegisterKernel.hpp" #include "cpu_kernels/GateImplementationsLM.hpp" -#include "cpu_kernels/GateImplementationsPI.hpp" namespace Pennylane::LightningQubit::Internal { int registerAllAvailableKernels_Float() { registerKernel(); - registerKernel(); return 1; } int registerAllAvailableKernels_Double() { registerKernel(); - registerKernel(); return 1; } } // namespace Pennylane::LightningQubit::Internal diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/RegisterKernels_x64.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/RegisterKernels_x64.cpp index cf4199fdff..f8b9c65a6f 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/RegisterKernels_x64.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/RegisterKernels_x64.cpp @@ -20,13 +20,11 @@ #include "RegisterKernel.hpp" #include "RuntimeInfo.hpp" #include "cpu_kernels/GateImplementationsLM.hpp" -#include "cpu_kernels/GateImplementationsPI.hpp" namespace Pennylane::LightningQubit::Internal { int registerAllAvailableKernels_Float() { using Pennylane::Util::RuntimeInfo; registerKernel(); - registerKernel(); if (RuntimeInfo::AVX2() && RuntimeInfo::FMA()) { registerKernelsAVX2_Float(); @@ -40,7 +38,6 @@ int registerAllAvailableKernels_Float() { int registerAllAvailableKernels_Double() { using Pennylane::Util::RuntimeInfo; registerKernel(); - registerKernel(); if (RuntimeInfo::AVX2() && RuntimeInfo::FMA()) { registerKernelsAVX2_Double(); diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp index 2b14653a04..16ad66e4e7 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp @@ -24,8 +24,6 @@ #include #include -#include - #include "BitUtil.hpp" // revWireParity #include "Error.hpp" #include "GateIndices.hpp" diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsPI.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsPI.cpp deleted file mode 100644 index 2594388bd3..0000000000 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsPI.cpp +++ /dev/null @@ -1,570 +0,0 @@ -// Copyright 2018-2023 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. -#include "GateImplementationsPI.hpp" - -namespace Pennylane::LightningQubit::Gates { -template -void GateImplementationsPI::applyDoubleExcitation( - std::complex *arr, std::size_t num_qubits, - const std::vector &wires, [[maybe_unused]] bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 4); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - const PrecisionT c = std::cos(angle / 2); - const PrecisionT s = inverse ? -std::sin(angle / 2) : std::sin(angle / 2); - - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i0 = 3; - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i1 = 12; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v3 = shiftedState[indices[i0]]; - const std::complex v12 = shiftedState[indices[i1]]; - - shiftedState[indices[i0]] = c * v3 - s * v12; - shiftedState[indices[i1]] = s * v3 + c * v12; - } -} - -template -void GateImplementationsPI::applyDoubleExcitationMinus( - std::complex *arr, std::size_t num_qubits, - const std::vector &wires, [[maybe_unused]] bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 4); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const PrecisionT c = std::cos(angle / 2); - const PrecisionT s = inverse ? -std::sin(angle / 2) : std::sin(angle / 2); - const std::complex e = - inverse ? std::exp(std::complex(0, angle / 2)) - : std::exp(-std::complex(0, angle / 2)); - - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i0 = 3; - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i1 = 12; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v3 = shiftedState[indices[i0]]; - const std::complex v12 = shiftedState[indices[i1]]; - // NOLINTBEGIN(readability-magic-numbers) - shiftedState[indices[0]] *= e; - shiftedState[indices[1]] *= e; - shiftedState[indices[2]] *= e; - shiftedState[indices[i0]] = c * v3 - s * v12; - shiftedState[indices[4]] *= e; - shiftedState[indices[5]] *= e; - shiftedState[indices[6]] *= e; - shiftedState[indices[7]] *= e; - shiftedState[indices[8]] *= e; - shiftedState[indices[9]] *= e; - shiftedState[indices[10]] *= e; - shiftedState[indices[11]] *= e; - shiftedState[indices[i1]] = s * v3 + c * v12; - shiftedState[indices[13]] *= e; - shiftedState[indices[14]] *= e; - shiftedState[indices[15]] *= e; - // NOLINTEND(readability-magic-numbers) - } -} - -template -void GateImplementationsPI::applyDoubleExcitationPlus( - std::complex *arr, std::size_t num_qubits, - const std::vector &wires, [[maybe_unused]] bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 4); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - const PrecisionT c = std::cos(angle / 2); - const PrecisionT s = inverse ? -std::sin(angle / 2) : std::sin(angle / 2); - const std::complex e = - inverse ? std::exp(-std::complex(0, angle / 2)) - : std::exp(std::complex(0, angle / 2)); - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i0 = 3; - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i1 = 12; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v3 = shiftedState[indices[i0]]; - const std::complex v12 = shiftedState[indices[i1]]; - // NOLINTBEGIN(readability-magic-numbers) - shiftedState[indices[0]] *= e; - shiftedState[indices[1]] *= e; - shiftedState[indices[2]] *= e; - shiftedState[indices[i0]] = c * v3 - s * v12; - shiftedState[indices[4]] *= e; - shiftedState[indices[5]] *= e; - shiftedState[indices[6]] *= e; - shiftedState[indices[7]] *= e; - shiftedState[indices[8]] *= e; - shiftedState[indices[9]] *= e; - shiftedState[indices[10]] *= e; - shiftedState[indices[11]] *= e; - shiftedState[indices[i1]] = s * v3 + c * v12; - shiftedState[indices[13]] *= e; - shiftedState[indices[14]] *= e; - shiftedState[indices[15]] *= e; - // NOLINTEND(readability-magic-numbers) - } -} - -template -auto GateImplementationsPI::applyGeneratorDoubleExcitation( - std::complex *arr, std::size_t num_qubits, - const std::vector &wires, [[maybe_unused]] bool adj) - -> PrecisionT { - PL_ASSERT(wires.size() == 4); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i0 = 3; - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i1 = 12; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v3 = shiftedState[indices[i0]]; - const std::complex v12 = shiftedState[indices[i1]]; - for (const std::size_t &i : indices) { - shiftedState[i] = std::complex{}; - } - - shiftedState[indices[i0]] = -v12 * Pennylane::Util::IMAG(); - shiftedState[indices[i1]] = v3 * Pennylane::Util::IMAG(); - } - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); -} - -template -auto GateImplementationsPI::applyGeneratorDoubleExcitationMinus( - std::complex *arr, std::size_t num_qubits, - const std::vector &wires, [[maybe_unused]] bool adj) - -> PrecisionT { - PL_ASSERT(wires.size() == 4); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i0 = 3; - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i1 = 12; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - shiftedState[indices[i0]] *= Pennylane::Util::IMAG(); - shiftedState[indices[i1]] *= -Pennylane::Util::IMAG(); - - std::swap(shiftedState[indices[i0]], shiftedState[indices[i1]]); - } - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); -} - -template -auto GateImplementationsPI::applyGeneratorDoubleExcitationPlus( - std::complex *arr, std::size_t num_qubits, - const std::vector &wires, [[maybe_unused]] bool adj) - -> PrecisionT { - PL_ASSERT(wires.size() == 4); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i0 = 3; - // NOLINTNEXTLINE(readability-magic-numbers) - const std::size_t i1 = 12; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - for (const std::size_t &i : indices) { - shiftedState[i] *= -1; - } - - shiftedState[indices[i0]] *= -Pennylane::Util::IMAG(); - shiftedState[indices[i1]] *= Pennylane::Util::IMAG(); - - std::swap(shiftedState[indices[i0]], shiftedState[indices[i1]]); - } - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); -} -// Matrix operations -template void GateImplementationsPI::applySingleQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); -template void GateImplementationsPI::applySingleQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); - -template void GateImplementationsPI::applyTwoQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); -template void GateImplementationsPI::applyTwoQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); - -template void GateImplementationsPI::applyMultiQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); -template void GateImplementationsPI::applyMultiQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); - -// Single-qubit gates -template void GateImplementationsPI::applyIdentity( - std::complex *, std::size_t, const std::vector &, bool); -template void GateImplementationsPI::applyIdentity( - std::complex *, std::size_t, const std::vector &, - bool); - -template void GateImplementationsPI::applyPauliX( - std::complex *, std::size_t, const std::vector &, bool); -template void -GateImplementationsPI::applyPauliX(std::complex *, std::size_t, - const std::vector &, - bool); - -template void GateImplementationsPI::applyPauliY( - std::complex *, std::size_t, const std::vector &, bool); -template void -GateImplementationsPI::applyPauliY(std::complex *, std::size_t, - const std::vector &, - bool); - -template void GateImplementationsPI::applyPauliZ( - std::complex *, std::size_t, const std::vector &, bool); -template void -GateImplementationsPI::applyPauliZ(std::complex *, std::size_t, - const std::vector &, - bool); - -template void GateImplementationsPI::applyHadamard( - std::complex *, std::size_t, const std::vector &, bool); -template void GateImplementationsPI::applyHadamard( - std::complex *, std::size_t, const std::vector &, - bool); - -template void -GateImplementationsPI::applyS(std::complex *, std::size_t, - const std::vector &, bool); -template void -GateImplementationsPI::applyS(std::complex *, std::size_t, - const std::vector &, bool); - -template void -GateImplementationsPI::applyT(std::complex *, std::size_t, - const std::vector &, bool); -template void -GateImplementationsPI::applyT(std::complex *, std::size_t, - const std::vector &, bool); - -template void GateImplementationsPI::applyPhaseShift( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyPhaseShift( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void -GateImplementationsPI::applyRX(std::complex *, std::size_t, - const std::vector &, - bool, float); -template void GateImplementationsPI::applyRX( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void -GateImplementationsPI::applyRY(std::complex *, std::size_t, - const std::vector &, - bool, float); -template void GateImplementationsPI::applyRY( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void -GateImplementationsPI::applyRZ(std::complex *, std::size_t, - const std::vector &, - bool, float); -template void GateImplementationsPI::applyRZ( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyRot( - std::complex *, std::size_t, const std::vector &, bool, - float, float, float); -template void GateImplementationsPI::applyRot( - std::complex *, std::size_t, const std::vector &, bool, - double, double, double); - -// Two-qubit gates -template void -GateImplementationsPI::applyCNOT(std::complex *, std::size_t, - const std::vector &, bool); -template void -GateImplementationsPI::applyCNOT(std::complex *, std::size_t, - const std::vector &, - bool); - -template void -GateImplementationsPI::applyCY(std::complex *, std::size_t, - const std::vector &, bool); -template void -GateImplementationsPI::applyCY(std::complex *, std::size_t, - const std::vector &, bool); - -template void -GateImplementationsPI::applyCZ(std::complex *, std::size_t, - const std::vector &, bool); -template void -GateImplementationsPI::applyCZ(std::complex *, std::size_t, - const std::vector &, bool); - -template void -GateImplementationsPI::applySWAP(std::complex *, std::size_t, - const std::vector &, bool); -template void -GateImplementationsPI::applySWAP(std::complex *, std::size_t, - const std::vector &, - bool); - -template void GateImplementationsPI::applyIsingXX( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyIsingXX( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyIsingXY( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyIsingXY( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyIsingYY( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyIsingYY( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyIsingZZ( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyIsingZZ( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyControlledPhaseShift( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyControlledPhaseShift( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyCRX( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyCRX( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyCRY( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyCRY( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyCRZ( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyCRZ( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyCRot( - std::complex *, std::size_t, const std::vector &, bool, - float, float, float); -template void GateImplementationsPI::applyCRot( - std::complex *, std::size_t, const std::vector &, bool, - double, double, double); - -template void GateImplementationsPI::applyToffoli( - std::complex *, std::size_t, const std::vector &, bool); -template void -GateImplementationsPI::applyToffoli(std::complex *, std::size_t, - const std::vector &, - bool); - -template void GateImplementationsPI::applyCSWAP( - std::complex *, std::size_t, const std::vector &, bool); -template void -GateImplementationsPI::applyCSWAP(std::complex *, std::size_t, - const std::vector &, - bool); - -template void GateImplementationsPI::applyMultiRZ( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyMultiRZ( - std::complex *, std::size_t, const std::vector &, bool, - double); - -/* QChem */ -template void GateImplementationsPI::applyDoubleExcitation( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyDoubleExcitation( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyDoubleExcitationMinus( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyDoubleExcitationMinus( - std::complex *, std::size_t, const std::vector &, bool, - double); - -template void GateImplementationsPI::applyDoubleExcitationPlus( - std::complex *, std::size_t, const std::vector &, bool, - float); -template void GateImplementationsPI::applyDoubleExcitationPlus( - std::complex *, std::size_t, const std::vector &, bool, - double); - -/* Generators */ -template auto GateImplementationsPI::applyGeneratorPhaseShift( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -template auto GateImplementationsPI::applyGeneratorPhaseShift( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -template auto PauliGenerator::applyGeneratorRX( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -template auto PauliGenerator::applyGeneratorRX( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -template auto PauliGenerator::applyGeneratorRY( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -template auto PauliGenerator::applyGeneratorRY( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -template auto PauliGenerator::applyGeneratorRZ( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -template auto PauliGenerator::applyGeneratorRZ( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -template auto -GateImplementationsPI::applyGeneratorIsingXX(std::complex *, std::size_t, - const std::vector &, - bool) -> float; -template auto GateImplementationsPI::applyGeneratorIsingXX( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -template auto GateImplementationsPI::applyGeneratorIsingXY( - std::complex *, std::size_t, const std::vector &, bool) - -> double; -template auto -GateImplementationsPI::applyGeneratorIsingXY(std::complex *, std::size_t, - const std::vector &, - bool) -> float; - -template auto -GateImplementationsPI::applyGeneratorIsingYY(std::complex *, std::size_t, - const std::vector &, - bool) -> float; -template auto GateImplementationsPI::applyGeneratorIsingYY( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -template auto GateImplementationsPI::applyGeneratorIsingZZ( - std::complex *, std::size_t, const std::vector &, bool) - -> double; -template auto -GateImplementationsPI::applyGeneratorIsingZZ(std::complex *, std::size_t, - const std::vector &, - bool) -> float; - -template auto -GateImplementationsPI::applyGeneratorCRX(std::complex *, std::size_t, - const std::vector &, bool) - -> float; -template auto -GateImplementationsPI::applyGeneratorCRX(std::complex *, std::size_t, - const std::vector &, bool) - -> double; - -template auto -GateImplementationsPI::applyGeneratorCRY(std::complex *, std::size_t, - const std::vector &, bool) - -> float; -template auto -GateImplementationsPI::applyGeneratorCRY(std::complex *, std::size_t, - const std::vector &, bool) - -> double; - -template auto -GateImplementationsPI::applyGeneratorCRZ(std::complex *, std::size_t, - const std::vector &, bool) - -> float; -template auto -GateImplementationsPI::applyGeneratorCRZ(std::complex *, std::size_t, - const std::vector &, bool) - -> double; - -template auto GateImplementationsPI::applyGeneratorControlledPhaseShift( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -template auto GateImplementationsPI::applyGeneratorControlledPhaseShift( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -/* QChem */ -template auto GateImplementationsPI::applyGeneratorDoubleExcitation( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -template auto GateImplementationsPI::applyGeneratorDoubleExcitation( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -template auto GateImplementationsPI::applyGeneratorDoubleExcitationMinus( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -template auto -GateImplementationsPI::applyGeneratorDoubleExcitationMinus( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -template auto GateImplementationsPI::applyGeneratorDoubleExcitationPlus( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -template auto GateImplementationsPI::applyGeneratorDoubleExcitationPlus( - std::complex *, std::size_t, const std::vector &, bool) - -> double; -} // namespace Pennylane::LightningQubit::Gates diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsPI.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsPI.hpp deleted file mode 100644 index 3249e9fdcf..0000000000 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsPI.hpp +++ /dev/null @@ -1,1394 +0,0 @@ -// Copyright 2018-2023 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 - * Defines gate operations with precomputed indices - */ -#pragma once - -/// @cond DEV -// Required for compilation with MSVC -#ifndef _USE_MATH_DEFINES -#define _USE_MATH_DEFINES // for C++ -#endif -/// @endcond - -#include -#include -#include - -#include "BitUtil.hpp" -#include "GateIndices.hpp" -#include "GateOperation.hpp" -#include "GatePragmas.hpp" -#include "Gates.hpp" -#include "KernelType.hpp" -#include "LinearAlgebra.hpp" -#include "PauliGenerator.hpp" -#include "Util.hpp" // ZERO - -/// @cond DEV -namespace { -using namespace Pennylane::Gates; -using namespace Pennylane::LightningQubit::Gates::Pragmas; -using Pennylane::Util::ZERO; -} // namespace -/// @endcond - -namespace Pennylane::LightningQubit::Gates { -/** - * @brief Kernel functions for gate operations with precomputed indices - * - * For given wires, we first compute the indices the gate applies to and use - * the computed indices to apply the operation. - * - * @tparam PrecisionT Floating point precision of underlying statevector data. - * */ -class GateImplementationsPI : public PauliGenerator { - public: - constexpr static KernelType kernel_id = KernelType::PI; - constexpr static std::string_view name = "PI"; - template - constexpr static std::size_t required_alignment = - std::alignment_of_v; - template - constexpr static uint32_t packed_bytes = sizeof(PrecisionT); - - constexpr static std::array implemented_gates = { - GateOperation::Identity, - GateOperation::PauliX, - GateOperation::PauliY, - GateOperation::PauliZ, - GateOperation::Hadamard, - GateOperation::S, - GateOperation::T, - GateOperation::PhaseShift, - GateOperation::RX, - GateOperation::RY, - GateOperation::RZ, - GateOperation::Rot, - GateOperation::CNOT, - GateOperation::CY, - GateOperation::CZ, - GateOperation::SWAP, - GateOperation::IsingXX, - GateOperation::IsingXY, - GateOperation::IsingYY, - GateOperation::IsingZZ, - GateOperation::ControlledPhaseShift, - GateOperation::CRX, - GateOperation::CRY, - GateOperation::CRZ, - GateOperation::CRot, - GateOperation::Toffoli, - GateOperation::CSWAP, - GateOperation::DoubleExcitation, - GateOperation::DoubleExcitationMinus, - GateOperation::DoubleExcitationPlus, - GateOperation::MultiRZ, - }; - - constexpr static std::array implemented_generators = { - GeneratorOperation::PhaseShift, - GeneratorOperation::RX, - GeneratorOperation::RY, - GeneratorOperation::RZ, - GeneratorOperation::IsingXX, - GeneratorOperation::IsingXY, - GeneratorOperation::IsingYY, - GeneratorOperation::IsingZZ, - GeneratorOperation::CRX, - GeneratorOperation::CRY, - GeneratorOperation::CRZ, - GeneratorOperation::ControlledPhaseShift, - GeneratorOperation::DoubleExcitation, - GeneratorOperation::DoubleExcitationMinus, - GeneratorOperation::DoubleExcitationPlus, - }; - - constexpr static std::array implemented_matrices = { - MatrixOperation::SingleQubitOp, - MatrixOperation::TwoQubitOp, - MatrixOperation::MultiQubitOp, - }; - - constexpr static std::array - implemented_controlled_gates{}; - - constexpr static std::array - implemented_controlled_generators{}; - - constexpr static std::array - implemented_controlled_matrices{}; - - /** - * @brief Apply a single qubit gate to the statevector. - * - * @param arr Pointer to the statevector. - * @param num_qubits Number of qubits. - * @param matrix Perfect square matrix in row-major order. - * @param wires Wires the gate applies to. - * @param inverse Indicate whether inverse should be taken. - */ - template - static inline void - applySingleQubitOp(std::complex *arr, std::size_t num_qubits, - const std::complex *matrix, - const std::vector &wires, - bool inverse = false) { - PL_ASSERT(wires.size() == 1); - - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - if (inverse) { - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v0 = shiftedState[indices[0]]; - const std::complex v1 = shiftedState[indices[1]]; - shiftedState[indices[0]] = - std::conj(matrix[0B00]) * v0 + - std::conj(matrix[0B10]) * - v1; // NOLINT(readability-magic-numbers) - shiftedState[indices[1]] = - std::conj(matrix[0B01]) * v0 + - std::conj(matrix[0B11]) * - v1; // NOLINT(readability-magic-numbers) - } - } else { - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v0 = shiftedState[indices[0]]; - const std::complex v1 = shiftedState[indices[1]]; - shiftedState[indices[0]] = - matrix[0B00] * v0 + - matrix[0B01] * v1; // NOLINT(readability-magic-numbers) - shiftedState[indices[1]] = - matrix[0B10] * v0 + - matrix[0B11] * v1; // NOLINT(readability-magic-numbers) - } - } - } - - /** - * @brief Apply a two qubit gate to the statevector. - * - * @param arr Pointer to the statevector. - * @param num_qubits Number of qubits. - * @param matrix Perfect square matrix in row-major order. - * @param wires Wires the gate applies to. - * @param inverse Indicate whether inverse should be taken. - */ - template - static inline void applyTwoQubitOp(std::complex *arr, - std::size_t num_qubits, - const std::complex *matrix, - const std::vector &wires, - bool inverse = false) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - if (inverse) { - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - const std::complex v00 = shiftedState[indices[0]]; - const std::complex v01 = shiftedState[indices[1]]; - const std::complex v10 = shiftedState[indices[2]]; - const std::complex v11 = shiftedState[indices[3]]; - - // NOLINTBEGIN(readability-magic-numbers) - shiftedState[indices[0]] = std::conj(matrix[0b0000]) * v00 + - std::conj(matrix[0b0100]) * v01 + - std::conj(matrix[0b1000]) * v10 + - std::conj(matrix[0b1100]) * v11; - shiftedState[indices[1]] = std::conj(matrix[0b0001]) * v00 + - std::conj(matrix[0b0101]) * v01 + - std::conj(matrix[0b1001]) * v10 + - std::conj(matrix[0b1101]) * v11; - shiftedState[indices[2]] = std::conj(matrix[0b0010]) * v00 + - std::conj(matrix[0b0110]) * v01 + - std::conj(matrix[0b1010]) * v10 + - std::conj(matrix[0b1110]) * v11; - shiftedState[indices[3]] = std::conj(matrix[0b0011]) * v00 + - std::conj(matrix[0b0111]) * v01 + - std::conj(matrix[0b1011]) * v10 + - std::conj(matrix[0b1111]) * v11; - // NOLINTEND(readability-magic-numbers) - } - } else { - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - const std::complex v00 = shiftedState[indices[0]]; - const std::complex v01 = shiftedState[indices[1]]; - const std::complex v10 = shiftedState[indices[2]]; - const std::complex v11 = shiftedState[indices[3]]; - - // NOLINTBEGIN(readability-magic-numbers) - shiftedState[indices[0]] = - matrix[0b0000] * v00 + matrix[0b0001] * v01 + - matrix[0b0010] * v10 + matrix[0b0011] * v11; - shiftedState[indices[1]] = - matrix[0b0100] * v00 + matrix[0b0101] * v01 + - matrix[0b0110] * v10 + matrix[0b0111] * v11; - shiftedState[indices[2]] = - matrix[0b1000] * v00 + matrix[0b1001] * v01 + - matrix[0b1010] * v10 + matrix[0b1011] * v11; - shiftedState[indices[3]] = - matrix[0b1100] * v00 + matrix[0b1101] * v01 + - matrix[0b1110] * v10 + matrix[0b1111] * v11; - // NOLINTEND(readability-magic-numbers) - } - } - } - - /** - * @brief Apply a given matrix directly to the statevector. - * - * @param arr Pointer to the statevector. - * @param num_qubits Number of qubits. - * @param matrix Perfect square matrix in row-major order. - * @param wires Wires the gate applies to. - * @param inverse Indicate whether inverse should be taken. - */ - template - static void - applyMultiQubitOp(std::complex *arr, std::size_t num_qubits, - const std::complex *matrix, - const std::vector &wires, bool inverse) { - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - std::vector> v(indices.size()); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - // Gather - std::size_t pos = 0; - for (const std::size_t &index : indices) { - v[pos] = shiftedState[index]; - pos++; - } - - // Apply + scatter - if (inverse) { - for (std::size_t i = 0; i < indices.size(); i++) { - std::size_t index = indices[i]; - shiftedState[index] = 0; - - for (std::size_t j = 0; j < indices.size(); j++) { - const std::size_t baseIndex = j * indices.size(); - shiftedState[index] += - std::conj(matrix[baseIndex + i]) * v[j]; - } - } - } else { - for (std::size_t i = 0; i < indices.size(); i++) { - std::size_t index = indices[i]; - shiftedState[index] = 0; - - const std::size_t baseIndex = i * indices.size(); - for (std::size_t j = 0; j < indices.size(); j++) { - shiftedState[index] += matrix[baseIndex + j] * v[j]; - } - } - } - } - } - - /* Single qubit operators */ - template - static void applyIdentity(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 1); - static_cast(arr); // No-op - static_cast(num_qubits); // No-op - static_cast(wires); // No-op - } - - template - static void applyPauliX(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - std::swap(shiftedState[indices[0]], shiftedState[indices[1]]); - } - } - - template - static void applyPauliY(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - std::complex v0 = shiftedState[indices[0]]; - shiftedState[indices[0]] = - std::complex{shiftedState[indices[1]].imag(), - -shiftedState[indices[1]].real()}; - shiftedState[indices[1]] = - std::complex{-v0.imag(), v0.real()}; - } - } - - template - static void applyPauliZ(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[1]] = -shiftedState[indices[1]]; - } - } - - template - static void applyHadamard(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - const std::complex v0 = shiftedState[indices[0]]; - const std::complex v1 = shiftedState[indices[1]]; - - shiftedState[indices[0]] = - Pennylane::Util::INVSQRT2() * (v0 + v1); - shiftedState[indices[1]] = - Pennylane::Util::INVSQRT2() * (v0 - v1); - } - } - - template - static void applyS(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - const std::complex shift = - (inverse) ? -Pennylane::Util::IMAG() - : Pennylane::Util::IMAG(); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[1]] *= shift; - } - } - - template - static void applyT(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const std::complex shift = - (inverse) ? std::conj(std::exp(std::complex( - 0, static_cast(M_PI / 4)))) - : std::exp(std::complex( - 0, static_cast(M_PI / 4))); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[1]] *= shift; - } - } - - /* Single qubit operators with a parameter */ - template - static void applyPhaseShift(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - bool inverse, ParamT angle) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - const std::complex s = - inverse ? std::conj(std::exp(std::complex(0, angle))) - : std::exp(std::complex(0, angle)); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[1]] *= s; - } - } - - template - static void applyRX(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const PrecisionT c = std::cos(angle / 2); - const PrecisionT js = - (inverse) ? -std::sin(-angle / 2) : std::sin(-angle / 2); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v0 = shiftedState[indices[0]]; - const std::complex v1 = shiftedState[indices[1]]; - shiftedState[indices[0]] = - c * v0 + js * std::complex{-v1.imag(), v1.real()}; - shiftedState[indices[1]] = - js * std::complex{-v0.imag(), v0.real()} + c * v1; - } - } - - template - static void applyRY(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const PrecisionT c = std::cos(angle / 2); - const PrecisionT s = - (inverse) ? -std::sin(angle / 2) : std::sin(angle / 2); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v0 = shiftedState[indices[0]]; - const std::complex v1 = shiftedState[indices[1]]; - shiftedState[indices[0]] = c * v0 - s * v1; - shiftedState[indices[1]] = s * v0 + c * v1; - } - } - - template - static void applyRZ(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const std::complex first = - std::complex(std::cos(angle / 2), -std::sin(angle / 2)); - const std::complex second = - std::complex(std::cos(angle / 2), std::sin(angle / 2)); - const std::complex shift1 = - (inverse) ? std::conj(first) : first; - const std::complex shift2 = - (inverse) ? std::conj(second) : second; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[0]] *= shift1; - shiftedState[indices[1]] *= shift2; - } - } - - template - static void applyRot(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT phi, ParamT theta, ParamT omega) { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const auto rot = getRot(phi, theta, omega); - - const std::complex t1 = - (inverse) ? std::conj(rot[0]) : rot[0]; - const std::complex t2 = (inverse) ? -rot[1] : rot[1]; - const std::complex t3 = (inverse) ? -rot[2] : rot[2]; - const std::complex t4 = - (inverse) ? std::conj(rot[3]) : rot[3]; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v0 = shiftedState[indices[0]]; - const std::complex v1 = shiftedState[indices[1]]; - shiftedState[indices[0]] = t1 * v0 + t2 * v1; - shiftedState[indices[1]] = t3 * v0 + t4 * v1; - } - } - - /* Two qubit operators */ - template - static void applyCNOT(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - std::swap(shiftedState[indices[2]], shiftedState[indices[3]]); - } - } - - template - static void applyCY(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - std::complex v2 = shiftedState[indices[2]]; - shiftedState[indices[2]] = - std::complex{shiftedState[indices[3]].imag(), - -shiftedState[indices[3]].real()}; - shiftedState[indices[3]] = - std::complex{-v2.imag(), v2.real()}; - } - } - - template - static void applyCZ(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[3]] *= -1; - } - } - - template - static void applySWAP(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - std::swap(shiftedState[indices[1]], shiftedState[indices[2]]); - } - } - - /* Two qubit operators with a parameter */ - template - static void applyIsingXX(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - bool inverse, ParamT angle) { - using ComplexT = std::complex; - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const PrecisionT cr = std::cos(angle / 2); - const PrecisionT sj = - inverse ? -std::sin(angle / 2) : std::sin(angle / 2); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - const auto v0 = shiftedState[indices[0]]; - const auto v1 = shiftedState[indices[1]]; - const auto v2 = shiftedState[indices[2]]; - const auto v3 = shiftedState[indices[3]]; - - shiftedState[indices[0]] = ComplexT{cr * real(v0) + sj * imag(v3), - cr * imag(v0) - sj * real(v3)}; - shiftedState[indices[1]] = ComplexT{cr * real(v1) + sj * imag(v2), - cr * imag(v1) - sj * real(v2)}; - shiftedState[indices[2]] = ComplexT{cr * real(v2) + sj * imag(v1), - cr * imag(v2) - sj * real(v1)}; - shiftedState[indices[3]] = ComplexT{cr * real(v3) + sj * imag(v0), - cr * imag(v3) - sj * real(v0)}; - } - } - - template - static void applyIsingXY(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - bool inverse, ParamT angle) { - using ComplexT = std::complex; - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const PrecisionT cr = std::cos(angle / 2); - const PrecisionT sj = - inverse ? -std::sin(angle / 2) : std::sin(angle / 2); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - const auto v0 = shiftedState[indices[0]]; - const auto v1 = shiftedState[indices[1]]; - const auto v2 = shiftedState[indices[2]]; - const auto v3 = shiftedState[indices[3]]; - - shiftedState[indices[0]] = ComplexT{real(v0), imag(v0)}; - shiftedState[indices[1]] = ComplexT{cr * real(v1) - sj * imag(v2), - cr * imag(v1) + sj * real(v2)}; - shiftedState[indices[2]] = ComplexT{cr * real(v2) - sj * imag(v1), - cr * imag(v2) + sj * real(v1)}; - shiftedState[indices[3]] = ComplexT{real(v3), imag(v3)}; - } - } - - template - static void applyIsingYY(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - bool inverse, ParamT angle) { - using ComplexT = std::complex; - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const PrecisionT cr = std::cos(angle / 2); - const PrecisionT sj = - inverse ? -std::sin(angle / 2) : std::sin(angle / 2); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - const auto v0 = shiftedState[indices[0]]; - const auto v1 = shiftedState[indices[1]]; - const auto v2 = shiftedState[indices[2]]; - const auto v3 = shiftedState[indices[3]]; - - shiftedState[indices[0]] = ComplexT{cr * real(v0) - sj * imag(v3), - cr * imag(v0) + sj * real(v3)}; - shiftedState[indices[1]] = ComplexT{cr * real(v1) + sj * imag(v2), - cr * imag(v1) - sj * real(v2)}; - shiftedState[indices[2]] = ComplexT{cr * real(v2) + sj * imag(v1), - cr * imag(v2) - sj * real(v1)}; - shiftedState[indices[3]] = ComplexT{cr * real(v3) - sj * imag(v0), - cr * imag(v3) + sj * real(v0)}; - } - } - - template - static void applyIsingZZ(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - bool inverse, ParamT angle) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const std::complex first = - std::complex{std::cos(angle / 2), -std::sin(angle / 2)}; - const std::complex second = - std::complex{std::cos(angle / 2), std::sin(angle / 2)}; - - const std::array, 2> shifts = { - (inverse) ? std::conj(first) : first, - (inverse) ? std::conj(second) : second}; - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - shiftedState[indices[0]] *= shifts[0]; - shiftedState[indices[1]] *= shifts[1]; - shiftedState[indices[2]] *= shifts[1]; - shiftedState[indices[3]] *= shifts[0]; - } - } - - template - static void applyControlledPhaseShift(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - bool inverse, ParamT angle) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const std::complex s = - inverse ? std::conj(std::exp(std::complex(0, angle))) - : std::exp(std::complex(0, angle)); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[3]] *= s; - } - } - - template - static void applyCRX(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const PrecisionT c = std::cos(angle / 2); - const PrecisionT js = - (inverse) ? -std::sin(-angle / 2) : std::sin(-angle / 2); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v0 = shiftedState[indices[2]]; - const std::complex v1 = shiftedState[indices[3]]; - shiftedState[indices[2]] = - c * v0 + js * std::complex{-v1.imag(), v1.real()}; - shiftedState[indices[3]] = - js * std::complex{-v0.imag(), v0.real()} + c * v1; - } - } - - template - static void applyCRY(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - const PrecisionT c = std::cos(angle / 2); - const PrecisionT s = - (inverse) ? -std::sin(angle / 2) : std::sin(angle / 2); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v0 = shiftedState[indices[2]]; - const std::complex v1 = shiftedState[indices[3]]; - shiftedState[indices[2]] = c * v0 - s * v1; - shiftedState[indices[3]] = s * v0 + c * v1; - } - } - - template - static void applyCRZ(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT angle) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - const std::complex m00 = - (inverse) ? std::complex(std::cos(angle / 2), - std::sin(angle / 2)) - : std::complex(std::cos(angle / 2), - -std::sin(angle / 2)); - const std::complex m11 = - (inverse) ? std::complex(std::cos(angle / 2), - -std::sin(angle / 2)) - : std::complex(std::cos(angle / 2), - std::sin(angle / 2)); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[2]] *= m00; - shiftedState[indices[3]] *= m11; - } - } - - template - static void applyCRot(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT phi, ParamT theta, ParamT omega) { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - const auto rot = getRot(phi, theta, omega); - - const std::complex t1 = - (inverse) ? std::conj(rot[0]) : rot[0]; - const std::complex t2 = (inverse) ? -rot[1] : rot[1]; - const std::complex t3 = (inverse) ? -rot[2] : rot[2]; - const std::complex t4 = - (inverse) ? std::conj(rot[3]) : rot[3]; - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const std::complex v0 = shiftedState[indices[2]]; - const std::complex v1 = shiftedState[indices[3]]; - shiftedState[indices[2]] = t1 * v0 + t2 * v1; - shiftedState[indices[3]] = t3 * v0 + t4 * v1; - } - } - - /* Three-qubit gate */ - template - static void applyToffoli(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 3); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - // Participating swapped indices - static const std::size_t op_idx0 = 6; - static const std::size_t op_idx1 = 7; - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - std::swap(shiftedState[indices[op_idx0]], - shiftedState[indices[op_idx1]]); - } - } - - template - static void applyCSWAP(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse) { - PL_ASSERT(wires.size() == 3); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - // Participating swapped indices - static const std::size_t op_idx0 = 5; - static const std::size_t op_idx1 = 6; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - std::swap(shiftedState[indices[op_idx0]], - shiftedState[indices[op_idx1]]); - } - } - - /* Four-qubit gates */ - template - static void - applyDoubleExcitation(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse, ParamT angle); - - template - static void - applyDoubleExcitationMinus(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse, ParamT angle); - - template - static void applyDoubleExcitationPlus(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse, - ParamT angle); - - /* Multi-qubit gates */ - template - static void applyMultiRZ(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool inverse, ParamT angle) { - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - const std::complex first = - std::complex{std::cos(angle / 2), -std::sin(angle / 2)}; - const std::complex second = - std::complex{std::cos(angle / 2), std::sin(angle / 2)}; - - const std::array, 2> shifts = { - (inverse) ? std::conj(first) : first, - (inverse) ? std::conj(second) : second}; - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - for (std::size_t k = 0; k < indices.size(); k++) { - shiftedState[indices[k]] *= shifts[std::popcount(k) % 2]; - } - } - } - - /* Gate generators */ - template - [[nodiscard]] static auto - applyGeneratorPhaseShift(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT { - PL_ASSERT(wires.size() == 1); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[0]] = std::complex{0.0, 0.0}; - } - // NOLINTNEXTLINE(readability-magic-numbers) - return static_cast(1.0); - } - - template - [[nodiscard]] static auto - applyGeneratorCRX(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[0]] = ZERO(); - shiftedState[indices[1]] = ZERO(); - - std::swap(shiftedState[indices[2]], shiftedState[indices[3]]); - } - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); - } - - template - [[nodiscard]] static auto - applyGeneratorIsingXX(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - std::swap(shiftedState[indices[0]], shiftedState[indices[3]]); - std::swap(shiftedState[indices[2]], shiftedState[indices[1]]); - } - - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); - } - - template - [[nodiscard]] static auto - applyGeneratorIsingXY(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - std::swap(shiftedState[indices[2]], shiftedState[indices[1]]); - shiftedState[indices[0]] = std::complex{0.0, 0.0}; - shiftedState[indices[3]] = std::complex{0.0, 0.0}; - } - - // NOLINTNEXTLINE(readability-magic-numbers) - return static_cast(0.5); - } - - template - [[nodiscard]] static auto - applyGeneratorIsingYY(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const auto v00 = shiftedState[indices[0]]; - shiftedState[indices[0]] = -shiftedState[indices[3]]; - shiftedState[indices[3]] = -v00; - std::swap(shiftedState[indices[2]], shiftedState[indices[1]]); - } - - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); - } - - template - [[nodiscard]] static auto - applyGeneratorIsingZZ(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - - shiftedState[indices[1]] *= -1; - shiftedState[indices[2]] *= -1; - } - - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); - } - - template - [[nodiscard]] static auto - applyGeneratorCRY(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - const auto v0 = shiftedState[indices[2]]; - shiftedState[indices[0]] = ZERO(); - shiftedState[indices[1]] = ZERO(); - shiftedState[indices[2]] = - -Pennylane::Util::IMAG() * shiftedState[indices[3]]; - shiftedState[indices[3]] = Pennylane::Util::IMAG() * v0; - } - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); - } - - template - [[nodiscard]] static auto - applyGeneratorCRZ(std::complex *arr, std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[0]] = ZERO(); - shiftedState[indices[1]] = ZERO(); - shiftedState[indices[3]] *= -1; - } - // NOLINTNEXTLINE(readability-magic-numbers) - return -static_cast(0.5); - } - - template - [[nodiscard]] static auto applyGeneratorControlledPhaseShift( - std::complex *arr, std::size_t num_qubits, - const std::vector &wires, [[maybe_unused]] bool adj) - -> PrecisionT { - PL_ASSERT(wires.size() == 2); - const auto [indices, externalIndices] = GateIndices(wires, num_qubits); - - for (const std::size_t &externalIndex : externalIndices) { - std::complex *shiftedState = arr + externalIndex; - shiftedState[indices[0]] = 0; - shiftedState[indices[1]] = 0; - shiftedState[indices[2]] = 0; - } - // NOLINTNEXTLINE(readability-magic-numbers) - return static_cast(1); - } - - template - [[nodiscard]] static auto - applyGeneratorDoubleExcitation(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT; - - template - [[nodiscard]] static auto applyGeneratorDoubleExcitationMinus( - std::complex *arr, std::size_t num_qubits, - const std::vector &wires, [[maybe_unused]] bool adj) - -> PrecisionT; - - template - [[nodiscard]] static auto - applyGeneratorDoubleExcitationPlus(std::complex *arr, - std::size_t num_qubits, - const std::vector &wires, - [[maybe_unused]] bool adj) -> PrecisionT; -}; - -// Matrix operations -extern template void GateImplementationsPI::applySingleQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); -extern template void GateImplementationsPI::applySingleQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); - -extern template void GateImplementationsPI::applyTwoQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); -extern template void GateImplementationsPI::applyTwoQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); - -extern template void GateImplementationsPI::applyMultiQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); -extern template void GateImplementationsPI::applyMultiQubitOp( - std::complex *, std::size_t, const std::complex *, - const std::vector &, bool); - -// Single-qubit gates -extern template void GateImplementationsPI::applyIdentity( - std::complex *, std::size_t, const std::vector &, bool); -extern template void GateImplementationsPI::applyIdentity( - std::complex *, std::size_t, const std::vector &, - bool); - -extern template void GateImplementationsPI::applyPauliX( - std::complex *, std::size_t, const std::vector &, bool); -extern template void -GateImplementationsPI::applyPauliX(std::complex *, std::size_t, - const std::vector &, - bool); - -extern template void GateImplementationsPI::applyPauliY( - std::complex *, std::size_t, const std::vector &, bool); -extern template void -GateImplementationsPI::applyPauliY(std::complex *, std::size_t, - const std::vector &, - bool); - -extern template void GateImplementationsPI::applyPauliZ( - std::complex *, std::size_t, const std::vector &, bool); -extern template void -GateImplementationsPI::applyPauliZ(std::complex *, std::size_t, - const std::vector &, - bool); - -extern template void GateImplementationsPI::applyHadamard( - std::complex *, std::size_t, const std::vector &, bool); -extern template void GateImplementationsPI::applyHadamard( - std::complex *, std::size_t, const std::vector &, - bool); - -extern template void -GateImplementationsPI::applyS(std::complex *, std::size_t, - const std::vector &, bool); -extern template void -GateImplementationsPI::applyS(std::complex *, std::size_t, - const std::vector &, bool); - -extern template void -GateImplementationsPI::applyT(std::complex *, std::size_t, - const std::vector &, bool); -extern template void -GateImplementationsPI::applyT(std::complex *, std::size_t, - const std::vector &, bool); - -extern template void GateImplementationsPI::applyPhaseShift( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyPhaseShift( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void -GateImplementationsPI::applyRX(std::complex *, std::size_t, - const std::vector &, - bool, float); -extern template void GateImplementationsPI::applyRX( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void -GateImplementationsPI::applyRY(std::complex *, std::size_t, - const std::vector &, - bool, float); -extern template void GateImplementationsPI::applyRY( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void -GateImplementationsPI::applyRZ(std::complex *, std::size_t, - const std::vector &, - bool, float); -extern template void GateImplementationsPI::applyRZ( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void GateImplementationsPI::applyRot( - std::complex *, std::size_t, const std::vector &, bool, - float, float, float); -extern template void GateImplementationsPI::applyRot( - std::complex *, std::size_t, const std::vector &, bool, - double, double, double); - -// Two-qubit gates -extern template void -GateImplementationsPI::applyCNOT(std::complex *, std::size_t, - const std::vector &, bool); -extern template void -GateImplementationsPI::applyCNOT(std::complex *, std::size_t, - const std::vector &, - bool); - -extern template void -GateImplementationsPI::applyCY(std::complex *, std::size_t, - const std::vector &, bool); -extern template void -GateImplementationsPI::applyCY(std::complex *, std::size_t, - const std::vector &, bool); - -extern template void -GateImplementationsPI::applyCZ(std::complex *, std::size_t, - const std::vector &, bool); -extern template void -GateImplementationsPI::applyCZ(std::complex *, std::size_t, - const std::vector &, bool); - -extern template void -GateImplementationsPI::applySWAP(std::complex *, std::size_t, - const std::vector &, bool); -extern template void -GateImplementationsPI::applySWAP(std::complex *, std::size_t, - const std::vector &, - bool); - -extern template void GateImplementationsPI::applyIsingXX( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyIsingXX( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void GateImplementationsPI::applyIsingXY( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyIsingXY( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void GateImplementationsPI::applyIsingYY( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyIsingYY( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void GateImplementationsPI::applyIsingZZ( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyIsingZZ( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void -GateImplementationsPI::applyControlledPhaseShift( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void -GateImplementationsPI::applyControlledPhaseShift( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void GateImplementationsPI::applyCRX( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyCRX( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void GateImplementationsPI::applyCRY( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyCRY( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void GateImplementationsPI::applyCRZ( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyCRZ( - std::complex *, std::size_t, const std::vector &, bool, - double); - -extern template void GateImplementationsPI::applyCRot( - std::complex *, std::size_t, const std::vector &, bool, - float, float, float); -extern template void GateImplementationsPI::applyCRot( - std::complex *, std::size_t, const std::vector &, bool, - double, double, double); - -extern template void GateImplementationsPI::applyToffoli( - std::complex *, std::size_t, const std::vector &, bool); -extern template void -GateImplementationsPI::applyToffoli(std::complex *, std::size_t, - const std::vector &, - bool); - -extern template void GateImplementationsPI::applyCSWAP( - std::complex *, std::size_t, const std::vector &, bool); -extern template void -GateImplementationsPI::applyCSWAP(std::complex *, std::size_t, - const std::vector &, - bool); - -extern template void GateImplementationsPI::applyMultiRZ( - std::complex *, std::size_t, const std::vector &, bool, - float); -extern template void GateImplementationsPI::applyMultiRZ( - std::complex *, std::size_t, const std::vector &, bool, - double); - -/* Generators */ -extern template auto GateImplementationsPI::applyGeneratorPhaseShift( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -extern template auto GateImplementationsPI::applyGeneratorPhaseShift( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -extern template auto PauliGenerator::applyGeneratorRX( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -extern template auto PauliGenerator::applyGeneratorRX( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -extern template auto PauliGenerator::applyGeneratorRY( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -extern template auto PauliGenerator::applyGeneratorRY( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -extern template auto PauliGenerator::applyGeneratorRZ( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -extern template auto PauliGenerator::applyGeneratorRZ( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -extern template auto -GateImplementationsPI::applyGeneratorIsingXX(std::complex *, std::size_t, - const std::vector &, - bool) -> float; -extern template auto GateImplementationsPI::applyGeneratorIsingXX( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -extern template auto GateImplementationsPI::applyGeneratorIsingXY( - std::complex *, std::size_t, const std::vector &, bool) - -> double; -extern template auto -GateImplementationsPI::applyGeneratorIsingXY(std::complex *, std::size_t, - const std::vector &, - bool) -> float; - -extern template auto -GateImplementationsPI::applyGeneratorIsingYY(std::complex *, std::size_t, - const std::vector &, - bool) -> float; -extern template auto GateImplementationsPI::applyGeneratorIsingYY( - std::complex *, std::size_t, const std::vector &, bool) - -> double; - -extern template auto GateImplementationsPI::applyGeneratorIsingZZ( - std::complex *, std::size_t, const std::vector &, bool) - -> double; -extern template auto -GateImplementationsPI::applyGeneratorIsingZZ(std::complex *, std::size_t, - const std::vector &, - bool) -> float; - -extern template auto -GateImplementationsPI::applyGeneratorCRX(std::complex *, std::size_t, - const std::vector &, bool) - -> float; -extern template auto -GateImplementationsPI::applyGeneratorCRX(std::complex *, std::size_t, - const std::vector &, bool) - -> double; - -extern template auto -GateImplementationsPI::applyGeneratorCRY(std::complex *, std::size_t, - const std::vector &, bool) - -> float; -extern template auto -GateImplementationsPI::applyGeneratorCRY(std::complex *, std::size_t, - const std::vector &, bool) - -> double; - -extern template auto -GateImplementationsPI::applyGeneratorCRZ(std::complex *, std::size_t, - const std::vector &, bool) - -> float; -extern template auto -GateImplementationsPI::applyGeneratorCRZ(std::complex *, std::size_t, - const std::vector &, bool) - -> double; - -extern template auto GateImplementationsPI::applyGeneratorControlledPhaseShift( - std::complex *, std::size_t, const std::vector &, bool) - -> float; -extern template auto GateImplementationsPI::applyGeneratorControlledPhaseShift( - std::complex *, std::size_t, const std::vector &, bool) - -> double; -} // namespace Pennylane::LightningQubit::Gates diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_DynamicDispatcher.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_DynamicDispatcher.cpp index ea2bfb7226..416d79da46 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_DynamicDispatcher.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_DynamicDispatcher.cpp @@ -29,7 +29,6 @@ /* Kernels */ #include "cpu_kernels/GateImplementationsLM.hpp" -#include "cpu_kernels/GateImplementationsPI.hpp" #include "TestHelpers.hpp" // createProductState, createRandomStateVectorData #include "TestHelpersWires.hpp" diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_Internal.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_Internal.cpp index ebcb5ced45..00fa3b2ffd 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_Internal.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_Internal.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include "TestHelpers.hpp" // createProductState, createZeroState #include "TestHelpersWires.hpp" // CombinationGenerator, PermutationGenerator -#include "cpu_kernels/GateImplementationsPI.hpp" #include @@ -30,9 +29,7 @@ /// @cond DEV namespace { -using namespace Pennylane::LightningQubit; using namespace Pennylane::Util; -using Pennylane::LightningQubit::Gates::GateImplementationsPI; } // namespace /// @endcond @@ -80,42 +77,6 @@ TEMPLATE_TEST_CASE("Approx", "[Test_Internal]", float, double) { } } -TEMPLATE_TEST_CASE("createProductState", "[Test_Internal]", float, double) { - using PrecisionT = TestType; - using ComplexT = std::complex; - - const auto margin = PrecisionT{1e-7}; - - SECTION("createProductState(\"+-0\") == |+-0> ") { - const auto st = createProductState("+-0"); - - auto expected = createZeroState(3); - GateImplementationsPI::applyHadamard(expected.data(), 3, {0}, false); - - GateImplementationsPI::applyPauliX(expected.data(), 3, {1}, false); - GateImplementationsPI::applyHadamard(expected.data(), 3, {1}, false); - - REQUIRE(st == approx(expected).margin(margin)); - } - SECTION("createProductState(\"+-0\") != |+-1> ") { - const auto st = createProductState("+-0"); - - auto expected = createZeroState(3); // |000> - GateImplementationsPI::applyHadamard(expected.data(), 3, {0}, - false); // |+00> - - GateImplementationsPI::applyPauliX(expected.data(), 3, {1}, - false); // |+10> - GateImplementationsPI::applyHadamard(expected.data(), 3, {1}, - false); // |+-0> - - GateImplementationsPI::applyPauliX(expected.data(), 3, {2}, - false); // |+-1> - - REQUIRE(st != approx(expected).margin(margin)); - } -} - std::size_t binomialCeff(std::size_t n, std::size_t r) { std::size_t num = 1; std::size_t dem = 1; diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_KernelMap.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_KernelMap.cpp index e833aa4520..6f94c3a574 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_KernelMap.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_KernelMap.cpp @@ -35,7 +35,7 @@ using Pennylane::Util::LightningException; TEST_CASE("Test PriorityDispatchSet", "[PriorityDispatchSet]") { auto pds = PriorityDispatchSet(); - pds.emplace(Pennylane::Gates::KernelType::PI, 10U, + pds.emplace(Pennylane::Gates::KernelType::LM, 10U, Util::IntegerInterval(10, 20)); SECTION("Test conflict") { @@ -45,7 +45,7 @@ TEST_CASE("Test PriorityDispatchSet", "[PriorityDispatchSet]") { } SECTION("Get Kernel") { - REQUIRE(pds.getKernel(15) == Pennylane::Gates::KernelType::PI); + REQUIRE(pds.getKernel(15) == Pennylane::Gates::KernelType::LM); PL_CHECK_THROWS_MATCHES(pds.getKernel(30), LightningException, "Cannot find a kernel"); } @@ -143,12 +143,12 @@ TEST_CASE("Test KernelMap functionalities", "[KernelMap]") { instance.assignKernelForOp( Pennylane::Gates::GateOperation::PauliX, Threading::SingleThread, CPUMemoryModel::Unaligned, 100, Util::full_domain(), - KernelType::PI); + KernelType::LM); REQUIRE(instance.getKernelMap(24, Threading::SingleThread, CPUMemoryModel::Unaligned) [Pennylane::Gates::GateOperation::PauliX] == - KernelType::PI); + KernelType::LM); instance.removeKernelForOp(Pennylane::Gates::GateOperation::PauliX, Threading::SingleThread, diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubit.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubit.cpp index efaf7451b6..6a11bc4a0d 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubit.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubit.cpp @@ -25,7 +25,6 @@ #include "StateVectorLQubitRaw.hpp" #include "TestHelpers.hpp" // createRandomStateVectorData #include "TestHelpersWires.hpp" -#include "cpu_kernels/GateImplementationsPI.hpp" /** * @file @@ -259,33 +258,6 @@ TEMPLATE_PRODUCT_TEST_CASE("StateVectorLQubit::applyMatrix with a pointer", REQUIRE_THROWS_WITH(state_vector.applyMatrix(m.data(), {}), Catch::Contains("must be larger than 0")); } - - SECTION("Test with different number of wires") { - const std::size_t num_qubits = 5; - for (std::size_t num_wires = 1; num_wires < num_qubits; num_wires++) { - VectorT st_data_1 = - createRandomStateVectorData(re, num_qubits); - VectorT st_data_2 = st_data_1; - - StateVectorT state_vector_1(st_data_1.data(), st_data_1.size()); - StateVectorT state_vector_2(st_data_2.data(), st_data_2.size()); - - std::vector wires(num_wires); - std::iota(wires.begin(), wires.end(), 0); - - const auto m = randomUnitary(re, num_wires); - - state_vector_1.applyMatrix(m, wires); - - Gates::GateImplementationsPI::applyMultiQubitOp( - state_vector_2.getData(), num_qubits, m.data(), wires, false); - - PrecisionT eps = std::numeric_limits::epsilon() * 10E3; - REQUIRE(isApproxEqual( - state_vector_1.getData(), state_vector_1.getLength(), - state_vector_2.getData(), state_vector_2.getLength(), eps)); - } - } } TEMPLATE_PRODUCT_TEST_CASE("StateVectorLQubit::applyOperations", diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp index 3c9f4abd90..b424e7e3cc 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/tests/Test_StateVectorLQubitManaged.cpp @@ -27,7 +27,6 @@ #include "StateVectorLQubitRaw.hpp" #include "TestHelpers.hpp" // createRandomStateVectorData, TestVector #include "TestHelpersWires.hpp" -#include "cpu_kernels/GateImplementationsPI.hpp" /** * @file diff --git a/pennylane_lightning/core/src/utils/TestKernels.hpp b/pennylane_lightning/core/src/utils/TestKernels.hpp index 8bf42d93d0..d75677e7ce 100644 --- a/pennylane_lightning/core/src/utils/TestKernels.hpp +++ b/pennylane_lightning/core/src/utils/TestKernels.hpp @@ -22,9 +22,7 @@ #include "TypeList.hpp" #include "cpu_kernels/GateImplementationsLM.hpp" -#include "cpu_kernels/GateImplementationsPI.hpp" using TestKernels = Pennylane::Util::TypeList< - Pennylane::LightningQubit::Gates::GateImplementationsPI, Pennylane::LightningQubit::Gates::GateImplementationsLM, void>; -#endif \ No newline at end of file +#endif