From 7107a7594ab1e711e42b33a4bc0a774c0c128bd1 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Tue, 10 Oct 2023 17:05:50 -0400 Subject: [PATCH] Add GateImplementationsLM::applyGeneratorDoubleExcitation(Minus/Plus) kernels. --- .../gates/AssignKernelMap_Default.cpp | 6 +- .../cpu_kernels/GateImplementationsLM.cpp | 176 ++++++++++++++++++ .../cpu_kernels/GateImplementationsLM.hpp | 41 ++++ 3 files changed, 220 insertions(+), 3 deletions(-) diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/AssignKernelMap_Default.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/AssignKernelMap_Default.cpp index 4e404d4d76..d47fdbc618 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/AssignKernelMap_Default.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/AssignKernelMap_Default.cpp @@ -203,13 +203,13 @@ void assignKernelsForGeneratorOp_Default() { all_qubit_numbers, KernelType::LM); instance.assignKernelForOp(GeneratorOperation::DoubleExcitation, all_threading, all_memory_model, - all_qubit_numbers, KernelType::PI); + all_qubit_numbers, KernelType::LM); instance.assignKernelForOp(GeneratorOperation::DoubleExcitationPlus, all_threading, all_memory_model, - all_qubit_numbers, KernelType::PI); + all_qubit_numbers, KernelType::LM); instance.assignKernelForOp(GeneratorOperation::DoubleExcitationMinus, all_threading, all_memory_model, - all_qubit_numbers, KernelType::PI); + all_qubit_numbers, KernelType::LM); instance.assignKernelForOp(GeneratorOperation::MultiRZ, all_threading, all_memory_model, all_qubit_numbers, diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.cpp index 8cba6c0cdc..1939d4c476 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.cpp @@ -203,6 +203,157 @@ auto GateImplementationsLM::applyGeneratorSingleExcitationPlus( return -static_cast(0.5); } +template +auto GateImplementationsLM::applyGeneratorDoubleExcitation( + std::complex *arr, std::size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) + -> PrecisionT { + using ComplexT = std::complex; + PL_ASSERT(wires.size() == 4); + + const std::size_t rev_wire0 = num_qubits - wires[3] - 1; + const std::size_t rev_wire1 = num_qubits - wires[2] - 1; + const std::size_t rev_wire2 = num_qubits - wires[1] - 1; + const std::size_t rev_wire3 = num_qubits - wires[0] - 1; + + const std::size_t rev_wire0_shift = static_cast(1U) + << rev_wire0; + const std::size_t rev_wire1_shift = static_cast(1U) + << rev_wire1; + const std::size_t rev_wire2_shift = static_cast(1U) + << rev_wire2; + const std::size_t rev_wire3_shift = static_cast(1U) + << rev_wire3; + + auto parity = revWireParity(rev_wire0, rev_wire1, rev_wire2, rev_wire3); + + for (std::size_t k = 0; k < exp2(num_qubits - 4); k++) { + + const std::size_t i0000 = + ((k << 4U) & parity[4]) | ((k << 3U) & parity[3]) | + ((k << 2U) & parity[2]) | ((k << 1U) & parity[1]) | (k & parity[0]); + const std::size_t i0001 = i0000 | rev_wire0_shift; + const std::size_t i0010 = i0000 | rev_wire1_shift; + const std::size_t i0011 = i0000 | rev_wire1_shift | rev_wire0_shift; + const std::size_t i0100 = i0000 | rev_wire2_shift; + const std::size_t i0101 = i0000 | rev_wire2_shift | rev_wire0_shift; + const std::size_t i0110 = i0000 | rev_wire2_shift | rev_wire1_shift; + const std::size_t i0111 = + i0000 | rev_wire2_shift | rev_wire1_shift | rev_wire0_shift; + const std::size_t i1000 = i0000 | rev_wire3_shift; + const std::size_t i1001 = i0000 | rev_wire3_shift | rev_wire0_shift; + const std::size_t i1010 = i0000 | rev_wire3_shift | rev_wire1_shift; + const std::size_t i1011 = + i0000 | rev_wire3_shift | rev_wire1_shift | rev_wire0_shift; + const std::size_t i1100 = i0000 | rev_wire3_shift | rev_wire2_shift; + const std::size_t i1101 = + i0000 | rev_wire3_shift | rev_wire2_shift | rev_wire0_shift; + const std::size_t i1110 = + i0000 | rev_wire3_shift | rev_wire2_shift | rev_wire1_shift; + const std::size_t i1111 = i0000 | rev_wire3_shift | rev_wire2_shift | + rev_wire1_shift | rev_wire0_shift; + + const ComplexT v3 = arr[i0011]; + const ComplexT v12 = arr[i1100]; + arr[i0000] = ComplexT{}; + arr[i0001] = ComplexT{}; + arr[i0010] = ComplexT{}; + arr[i0011] = v12 * ComplexT{0, -1}; + arr[i0100] = ComplexT{}; + arr[i0101] = ComplexT{}; + arr[i0110] = ComplexT{}; + arr[i0111] = ComplexT{}; + arr[i1000] = ComplexT{}; + arr[i1001] = ComplexT{}; + arr[i1010] = ComplexT{}; + arr[i1011] = ComplexT{}; + arr[i1100] = v3 * ComplexT{0, 1}; + arr[i1101] = ComplexT{}; + arr[i1110] = ComplexT{}; + arr[i1111] = ComplexT{}; + } + // NOLINTNEXTLINE(readability - magic - numbers) + return -static_cast(0.5); +} + +template +auto GateImplementationsLM::applyGeneratorDoubleExcitationMinus( + std::complex *arr, std::size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) + -> PrecisionT { + using ComplexT = std::complex; + PL_ASSERT(wires.size() == 4); + + const std::size_t rev_wire0 = num_qubits - wires[3] - 1; + const std::size_t rev_wire1 = num_qubits - wires[2] - 1; + const std::size_t rev_wire2 = num_qubits - wires[1] - 1; + const std::size_t rev_wire3 = num_qubits - wires[0] - 1; + + const std::size_t rev_wire0_shift = static_cast(1U) + << rev_wire0; + const std::size_t rev_wire1_shift = static_cast(1U) + << rev_wire1; + const std::size_t rev_wire2_shift = static_cast(1U) + << rev_wire2; + const std::size_t rev_wire3_shift = static_cast(1U) + << rev_wire3; + + auto parity = revWireParity(rev_wire0, rev_wire1, rev_wire2, rev_wire3); + + for (std::size_t k = 0; k < exp2(num_qubits - 4); k++) { + const std::size_t i0000 = + ((k << 4U) & parity[4]) | ((k << 3U) & parity[3]) | + ((k << 2U) & parity[2]) | ((k << 1U) & parity[1]) | (k & parity[0]); + const std::size_t i0011 = i0000 | rev_wire1_shift | rev_wire0_shift; + const std::size_t i1100 = i0000 | rev_wire3_shift | rev_wire2_shift; + + arr[i0011] *= ComplexT{0, 1}; + arr[i1100] *= ComplexT{0, -1}; + swap(arr[i1100], arr[i0011]); + } + // NOLINTNEXTLINE(readability - magic - numbers) + return -static_cast(0.5); +} + +template +auto GateImplementationsLM::applyGeneratorDoubleExcitationPlus( + std::complex *arr, std::size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) + -> PrecisionT { + using ComplexT = std::complex; + PL_ASSERT(wires.size() == 4); + + const std::size_t rev_wire0 = num_qubits - wires[3] - 1; + const std::size_t rev_wire1 = num_qubits - wires[2] - 1; + const std::size_t rev_wire2 = num_qubits - wires[1] - 1; + const std::size_t rev_wire3 = num_qubits - wires[0] - 1; + + const std::size_t rev_wire0_shift = static_cast(1U) + << rev_wire0; + const std::size_t rev_wire1_shift = static_cast(1U) + << rev_wire1; + const std::size_t rev_wire2_shift = static_cast(1U) + << rev_wire2; + const std::size_t rev_wire3_shift = static_cast(1U) + << rev_wire3; + + auto parity = revWireParity(rev_wire0, rev_wire1, rev_wire2, rev_wire3); + + for (std::size_t k = 0; k < exp2(num_qubits - 4); k++) { + const std::size_t i0000 = + ((k << 4U) & parity[4]) | ((k << 3U) & parity[3]) | + ((k << 2U) & parity[2]) | ((k << 1U) & parity[1]) | (k & parity[0]); + const std::size_t i0011 = i0000 | rev_wire1_shift | rev_wire0_shift; + const std::size_t i1100 = i0000 | rev_wire3_shift | rev_wire2_shift; + + arr[i0011] *= ComplexT{0, -1}; + arr[i1100] *= ComplexT{0, 1}; + swap(arr[i1100], arr[i0011]); + } + // NOLINTNEXTLINE(readability - magic - numbers) + return static_cast(0.5); +} + // Explicit instantiation starts /* Matrix operations */ template void GateImplementationsLM::applySingleQubitOp( @@ -571,6 +722,31 @@ template auto GateImplementationsLM::applyGeneratorSingleExcitationPlus( std::complex *arr, size_t num_qubits, const std::vector &wires, [[maybe_unused]] bool adj) -> double; +template auto GateImplementationsLM::applyGeneratorDoubleExcitation( + std::complex *arr, size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) -> float; + +template auto GateImplementationsLM::applyGeneratorDoubleExcitation( + std::complex *arr, size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) -> double; + +template auto GateImplementationsLM::applyGeneratorDoubleExcitationMinus( + std::complex *arr, size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) -> float; + +template auto +GateImplementationsLM::applyGeneratorDoubleExcitationMinus( + std::complex *arr, size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) -> double; + +template auto GateImplementationsLM::applyGeneratorDoubleExcitationPlus( + std::complex *arr, size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) -> float; + +template auto GateImplementationsLM::applyGeneratorDoubleExcitationPlus( + std::complex *arr, size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) -> double; + // Explicit instantiations ends } // namespace Pennylane::LightningQubit::Gates 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 4df61f2c91..3d39416c97 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 @@ -139,6 +139,9 @@ class GateImplementationsLM : public PauliGenerator { GeneratorOperation::SingleExcitation, GeneratorOperation::SingleExcitationMinus, GeneratorOperation::SingleExcitationPlus, + GeneratorOperation::DoubleExcitation, + GeneratorOperation::DoubleExcitationMinus, + GeneratorOperation::DoubleExcitationPlus, GeneratorOperation::MultiRZ, }; @@ -1594,6 +1597,26 @@ class GateImplementationsLM : public PauliGenerator { const std::vector &wires, [[maybe_unused]] bool adj) -> PrecisionT; + template + [[nodiscard]] static auto + applyGeneratorDoubleExcitation(std::complex *arr, + size_t num_qubits, + const std::vector &wires, + [[maybe_unused]] bool adj) -> PrecisionT; + + template + [[nodiscard]] static auto applyGeneratorDoubleExcitationMinus( + std::complex *arr, size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) + -> PrecisionT; + + template + [[nodiscard]] static auto + applyGeneratorDoubleExcitationPlus(std::complex *arr, + size_t num_qubits, + const std::vector &wires, + [[maybe_unused]] bool adj) -> PrecisionT; + template [[nodiscard]] static auto applyGeneratorMultiRZ(std::complex *arr, size_t num_qubits, @@ -1942,6 +1965,24 @@ extern template auto GateImplementationsLM::applyGeneratorSingleExcitationPlus( extern template auto GateImplementationsLM::applyGeneratorSingleExcitationPlus( std::complex *, size_t, const std::vector &, bool) -> float; +extern template auto GateImplementationsLM::applyGeneratorDoubleExcitation( + std::complex *, size_t, const std::vector &, bool) + -> double; +extern template auto GateImplementationsLM::applyGeneratorDoubleExcitation( + std::complex *, size_t, const std::vector &, bool) -> float; + +extern template auto GateImplementationsLM::applyGeneratorDoubleExcitationMinus( + std::complex *, size_t, const std::vector &, bool) + -> double; +extern template auto GateImplementationsLM::applyGeneratorDoubleExcitationMinus( + std::complex *, size_t, const std::vector &, bool) -> float; + +extern template auto GateImplementationsLM::applyGeneratorDoubleExcitationPlus( + std::complex *, size_t, const std::vector &, bool) + -> double; +extern template auto GateImplementationsLM::applyGeneratorDoubleExcitationPlus( + std::complex *, size_t, const std::vector &, bool) -> float; + extern template auto GateImplementationsLM::applyGeneratorMultiRZ(std::complex *, size_t, const std::vector &, bool)