From bb2ab316e90cb4b118f212e90c2695d63426b925 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Mon, 12 Feb 2024 21:43:58 +0000 Subject: [PATCH 01/16] Initial commit for C(MultiRZ). --- .../core/src/gates/Constant.hpp | 8 ++++ .../core/src/gates/GateOperation.hpp | 3 ++ .../gates/AssignKernelMap_Default.cpp | 7 +++ .../gates/OpToMemberFuncPtr.hpp | 12 +++++ .../cpu_kernels/GateImplementationsLM.hpp | 44 +++++++++++++++++-- .../lightning_qubit/lightning_qubit.py | 1 + tests/test_gates.py | 8 ++-- 7 files changed, 77 insertions(+), 6 deletions(-) diff --git a/pennylane_lightning/core/src/gates/Constant.hpp b/pennylane_lightning/core/src/gates/Constant.hpp index ded124eb5e..f9090d9f6c 100644 --- a/pennylane_lightning/core/src/gates/Constant.hpp +++ b/pennylane_lightning/core/src/gates/Constant.hpp @@ -27,12 +27,17 @@ namespace Pennylane::Gates::Constant { * @brief List of multi-qubit gates */ [[maybe_unused]] constexpr std::array multi_qubit_gates{GateOperation::MultiRZ}; +[[maybe_unused]] constexpr std::array controlled_multi_qubit_gates{ + ControlledGateOperation::MultiRZ}; /** * @brief List of multi-qubit generators */ [[maybe_unused]] constexpr std::array multi_qubit_generators{ GeneratorOperation::MultiRZ, }; +[[maybe_unused]] constexpr std::array controlled_multi_qubit_generators{ + GeneratorOperation::MultiRZ, +}; /** * @brief List of multi-qubit matrix operation */ @@ -107,6 +112,7 @@ using CGateView = typename std::pair; "DoubleExcitationMinus"}, CGateView{ControlledGateOperation::DoubleExcitationPlus, "DoubleExcitationPlus"}, + CGateView{ControlledGateOperation::MultiRZ, "MultiRZ"}, }; /** @@ -168,6 +174,7 @@ using CGeneratorView = "DoubleExcitationMinus"}, CGeneratorView{ControlledGeneratorOperation::DoubleExcitationPlus, "DoubleExcitationPlus"}, + CGeneratorView{ControlledGeneratorOperation::MultiRZ, "MultiRZ"}, }; /** @@ -364,5 +371,6 @@ using CGateNParams = typename std::pair; CGateNParams{ControlledGateOperation::DoubleExcitation, 1}, CGateNParams{ControlledGateOperation::DoubleExcitationMinus, 1}, CGateNParams{ControlledGateOperation::DoubleExcitationPlus, 1}, + CGateNParams{ControlledGateOperation::MultiRZ, 1}, }; } // namespace Pennylane::Gates::Constant diff --git a/pennylane_lightning/core/src/gates/GateOperation.hpp b/pennylane_lightning/core/src/gates/GateOperation.hpp index 0b9e4c1105..2c8ae16fa6 100644 --- a/pennylane_lightning/core/src/gates/GateOperation.hpp +++ b/pennylane_lightning/core/src/gates/GateOperation.hpp @@ -94,6 +94,8 @@ enum class ControlledGateOperation : uint32_t { DoubleExcitation, DoubleExcitationMinus, DoubleExcitationPlus, + /* Multi-qubit gates */ + MultiRZ, /* END (placeholder) */ END }; @@ -143,6 +145,7 @@ enum class ControlledGeneratorOperation : uint32_t { DoubleExcitation, DoubleExcitationMinus, DoubleExcitationPlus, + MultiRZ, /* END (placeholder) */ END }; 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 b39816087b..b9b9197551 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 @@ -295,6 +295,10 @@ void assignKernelsForControlledGateOp_Default() { instance.assignKernelForOp(ControlledGateOperation::DoubleExcitationPlus, all_threading, all_memory_model, all_qubit_numbers, KernelType::LM); + /* Multi-qubit gates */ + instance.assignKernelForOp(ControlledGateOperation::MultiRZ, all_threading, + all_memory_model, all_qubit_numbers, + KernelType::LM); } void assignKernelsForControlledGeneratorOp_Default() { auto &instance = @@ -342,6 +346,9 @@ void assignKernelsForControlledGeneratorOp_Default() { instance.assignKernelForOp( ControlledGeneratorOperation::DoubleExcitationPlus, all_threading, all_memory_model, all_qubit_numbers, KernelType::LM); + instance.assignKernelForOp(ControlledGeneratorOperation::MultiRZ, + all_threading, all_memory_model, + all_qubit_numbers, KernelType::LM); } void assignKernelsForControlledMatrixOp_Default() { auto &instance = diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp index c20531bd6f..e993603b92 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp @@ -404,6 +404,12 @@ struct ControlledGateOpToMemberFuncPtr< &GateImplementation::template applyNCDoubleExcitationPlus; }; +template +struct ControlledGateOpToMemberFuncPtr { + constexpr static auto value = + &GateImplementation::template applyNCMultiRZ; +}; /** * @brief Return a specific member function pointer for a given generator @@ -644,6 +650,12 @@ struct ControlledGeneratorOpToMemberFuncPtr< &GateImplementation::template applyNCGeneratorDoubleExcitationPlus< PrecisionT>; }; +template +struct ControlledGeneratorOpToMemberFuncPtr< + PrecisionT, GateImplementation, ControlledGeneratorOperation::MultiRZ> { + constexpr static auto value = + &GateImplementation::template applyNCGeneratorMultiRZ; +}; /** * @brief Matrix operation to member function pointer 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 ec5b594cbb..b7b8b3d7fb 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 @@ -171,6 +171,7 @@ class GateImplementationsLM : public PauliGenerator { ControlledGateOperation::DoubleExcitation, ControlledGateOperation::DoubleExcitationMinus, ControlledGateOperation::DoubleExcitationPlus, + ControlledGateOperation::MultiRZ, }; constexpr static std::array implemented_generators = { @@ -522,9 +523,10 @@ class GateImplementationsLM : public PauliGenerator { } } auto core_function = - [dim, mat](std::complex *arr, - const std::vector &indices, - const std::vector> &coeffs_in) { + [dim, + &mat](std::complex *arr, + const std::vector &indices, + const std::vector> &coeffs_in) { for (std::size_t i = 0; i < dim; i++) { const auto index = indices[i]; arr[index] = 0.0; @@ -1832,6 +1834,42 @@ class GateImplementationsLM : public PauliGenerator { } } + template + static void applyNCMultiRZ(std::complex *arr, + std::size_t num_qubits, + const std::vector &controlled_wires, + const std::vector &controlled_values, + const std::vector &wires, + bool inverse, ParamT angle) { + static constexpr std::size_t one{1}; + const std::size_t dim = one << wires.size(); + + 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}; + std::size_t wires_parity = 0U; + for (std::size_t wire : wires) { + wires_parity |= + (static_cast(1U) << (num_qubits - wire - 1)); + } + auto core_function = + [dim, wires_parity, &shifts]( + std::complex *arr, + const std::vector &indices, + [[maybe_unused]] const std::vector> + &coeffs_in) { + for (auto &k : indices) { + arr[k] *= shifts[std::popcount(k & wires_parity) % 2]; + } + }; + applyNCN(arr, num_qubits, controlled_wires, controlled_values, wires, + core_function); + } + /* Generators */ /** diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index 1144a89765..ddd6764d79 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -143,6 +143,7 @@ def _state_dtype(dtype): "C(DoubleExcitation)", "C(DoubleExcitationMinus)", "C(DoubleExcitationPlus)", + "C(MultiRZ)", "CRot", "IsingXX", "IsingYY", diff --git a/tests/test_gates.py b/tests/test_gates.py index aef3ba33cb..f5a11bd152 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -362,6 +362,7 @@ def circuit(): qml.DoubleExcitation, qml.DoubleExcitationMinus, qml.DoubleExcitationPlus, + qml.MultiRZ, ], ) @pytest.mark.parametrize("control_value", [False, True]) @@ -371,14 +372,15 @@ def test_controlled_qubit_gates(operation, n_qubits, control_value, tol): dev_def = qml.device("default.qubit", wires=n_qubits) dev = qml.device(device_name, wires=n_qubits) threshold = 250 - for n_wires in range(operation.num_wires + 1, operation.num_wires + 4): + num_wires = max(operation.num_wires, 1) + for n_wires in range(num_wires + 1, num_wires + 4): wire_lists = list(itertools.permutations(range(0, n_qubits), n_wires)) n_perms = len(wire_lists) * n_wires if n_perms > threshold: wire_lists = wire_lists[0 :: (n_perms // threshold)] for all_wires in wire_lists: - target_wires = all_wires[0 : operation.num_wires] - control_wires = all_wires[operation.num_wires :] + target_wires = all_wires[0:num_wires] + control_wires = all_wires[num_wires:] init_state = np.random.rand(2**n_qubits) + 1.0j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) From dba9240b1a9131282c262cadccc869675f44814b Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Tue, 13 Feb 2024 15:34:48 +0000 Subject: [PATCH 02/16] Add an-ctrl multirz generator. --- .../cpu_kernels/GateImplementationsLM.hpp | 44 ++++++++++++++++--- tests/test_adjoint_jacobian.py | 11 ++--- 2 files changed, 45 insertions(+), 10 deletions(-) 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 b7b8b3d7fb..58ea7de2ec 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 @@ -211,6 +211,7 @@ class GateImplementationsLM : public PauliGenerator { ControlledGeneratorOperation::DoubleExcitation, ControlledGeneratorOperation::DoubleExcitationMinus, ControlledGeneratorOperation::DoubleExcitationPlus, + ControlledGeneratorOperation::MultiRZ, }; constexpr static std::array implemented_matrices = { @@ -485,7 +486,6 @@ class GateImplementationsLM : public PauliGenerator { const auto indices = parity2indices(k, parity, rev_wire_shifts, n_contr, rev_wires); std::vector> coeffs_in(dim, 0.0); - for (std::size_t i = 0; i < dim; i++) { coeffs_in[i] = arr[indices[i]]; } @@ -2249,7 +2249,6 @@ class GateImplementationsLM : public PauliGenerator { std::complex *arr, size_t num_qubits, const std::vector &controlled_wires, const std::vector &controlled_values, - const std::vector &wires, [[maybe_unused]] bool adj) -> PrecisionT { auto core_function = [](std::complex *arr, @@ -2283,7 +2282,6 @@ class GateImplementationsLM : public PauliGenerator { std::complex *arr, size_t num_qubits, const std::vector &controlled_wires, const std::vector &controlled_values, - const std::vector &wires, [[maybe_unused]] bool adj) -> PrecisionT { auto core_function = [](std::complex *arr, @@ -2429,7 +2427,6 @@ class GateImplementationsLM : public PauliGenerator { std::complex *arr, size_t num_qubits, const std::vector &controlled_wires, const std::vector &controlled_values, - const std::vector &wires, [[maybe_unused]] bool adj) -> PrecisionT { using ComplexT = std::complex; @@ -2509,7 +2506,6 @@ class GateImplementationsLM : public PauliGenerator { std::complex *arr, size_t num_qubits, const std::vector &controlled_wires, const std::vector &controlled_values, - const std::vector &wires, [[maybe_unused]] bool adj) -> PrecisionT { using ComplexT = std::complex; @@ -2563,5 +2559,43 @@ class GateImplementationsLM : public PauliGenerator { // NOLINTNEXTLINE(readability-magic-numbers) return -static_cast(0.5); } + + template + [[nodiscard]] static auto + applyNCGeneratorMultiRZ(std::complex *arr, size_t num_qubits, + const std::vector &controlled_wires, + const std::vector &controlled_values, + const std::vector &wires, + [[maybe_unused]] bool adj) -> PrecisionT { + PL_ABORT_IF_NOT(controlled_wires.size() == controlled_values.size(), + "`controlled_wires` must have the same size as " + "`controlled_values`."); + constexpr size_t one{1}; + constexpr std::complex zero{0.0}; + auto ctrls_mask = static_cast(0U); + for (size_t i = 0; i < controlled_wires.size(); i++) { + ctrls_mask |= (static_cast(controlled_values[i]) + << (num_qubits - controlled_wires[i] - 1)); + } + auto ctrls_parity = static_cast(0U); + for (size_t i = 0; i < controlled_wires.size(); i++) { + ctrls_parity |= (one << (num_qubits - controlled_wires[i] - 1)); + } + auto wires_parity = static_cast(0U); + for (size_t wire : wires) { + wires_parity |= (one << (num_qubits - wire - 1)); + } + PL_LOOP_PARALLEL(1) + for (size_t k = 0; k < exp2(num_qubits); k++) { + if (ctrls_mask == (ctrls_parity & k)) { + arr[k] *= static_cast( + 1 - 2 * int(std::popcount(k & wires_parity) % 2)); + } else { + arr[k] = zero; + } + } + // NOLINTNEXTLINE(readability-magic-numbers) + return -static_cast(0.5); + } }; } // namespace Pennylane::LightningQubit::Gates diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py index 422ad06eef..4cf59ec6cd 100644 --- a/tests/test_adjoint_jacobian.py +++ b/tests/test_adjoint_jacobian.py @@ -715,6 +715,7 @@ def circuit(x, y, z): qml.DoubleExcitation, qml.DoubleExcitationMinus, qml.DoubleExcitationPlus, + qml.MultiRZ, ], ) @pytest.mark.parametrize("control_value", [False, True]) @@ -728,18 +729,18 @@ def test_controlled_jacobian(self, par, n_qubits, control_value, operation, tol) init_state = np.random.rand(2**n_qubits) + 1.0j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) init_state = np.array(init_state, requires_grad=False) - - if operation.num_wires > n_qubits: + num_wires = max(operation.num_wires, 1) + if num_wires > n_qubits: return - for n_controls in range(0, n_qubits - operation.num_wires): - control_wires = range(n_controls, n_qubits - operation.num_wires) + for n_controls in range(0, n_qubits - num_wires): + control_wires = range(n_controls, n_qubits - num_wires) def circuit(p): qml.StatePrep(init_state, wires=range(n_qubits)) qml.RX(p[0], 0) qml.ctrl( - operation(p[1], wires=range(n_qubits - operation.num_wires, n_qubits)), + operation(p[1], wires=range(n_qubits - num_wires, n_qubits)), control_wires, control_values=[ control_value or bool(i % 2) for i, _ in enumerate(control_wires) From da2bfffd615ed2bc929c46ab28fcb0e359834a57 Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Tue, 13 Feb 2024 15:36:35 +0000 Subject: [PATCH 03/16] Auto update version --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 5dd26d23ce..af34c02f2a 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.35.0-dev13" +__version__ = "0.35.0-dev14" From ff744f3e5817790c3f59e6499d3abc3187a16449 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Tue, 13 Feb 2024 18:09:39 +0000 Subject: [PATCH 04/16] Add C(Rot) gate and tests. --- .../core/src/gates/Constant.hpp | 3 + .../core/src/gates/GateOperation.hpp | 1 + .../gates/AssignKernelMap_Default.cpp | 3 + .../gates/OpToMemberFuncPtr.hpp | 30 ++++- .../cpu_kernels/GateImplementationsLM.hpp | 108 +++++++++--------- .../lightning_qubit/lightning_qubit.py | 1 + tests/test_adjoint_jacobian.py | 28 +++-- tests/test_gates.py | 3 +- 8 files changed, 115 insertions(+), 62 deletions(-) diff --git a/pennylane_lightning/core/src/gates/Constant.hpp b/pennylane_lightning/core/src/gates/Constant.hpp index f9090d9f6c..617d160c16 100644 --- a/pennylane_lightning/core/src/gates/Constant.hpp +++ b/pennylane_lightning/core/src/gates/Constant.hpp @@ -97,6 +97,7 @@ using CGateView = typename std::pair; CGateView{ControlledGateOperation::RX, "RX"}, CGateView{ControlledGateOperation::RY, "RY"}, CGateView{ControlledGateOperation::RZ, "RZ"}, + CGateView{ControlledGateOperation::Rot, "Rot"}, CGateView{ControlledGateOperation::SWAP, "SWAP"}, CGateView{ControlledGateOperation::IsingXX, "IsingXX"}, CGateView{ControlledGateOperation::IsingXY, "IsingXY"}, @@ -247,6 +248,7 @@ using CGateNWires = typename std::pair; CGateNWires{ControlledGateOperation::RX, 1}, CGateNWires{ControlledGateOperation::RY, 1}, CGateNWires{ControlledGateOperation::RZ, 1}, + CGateNWires{ControlledGateOperation::Rot, 1}, CGateNWires{ControlledGateOperation::SWAP, 2}, CGateNWires{ControlledGateOperation::IsingXX, 2}, CGateNWires{ControlledGateOperation::IsingXY, 2}, @@ -360,6 +362,7 @@ using CGateNParams = typename std::pair; CGateNParams{ControlledGateOperation::RX, 1}, CGateNParams{ControlledGateOperation::RY, 1}, CGateNParams{ControlledGateOperation::RZ, 1}, + CGateNParams{ControlledGateOperation::Rot, 3}, CGateNParams{ControlledGateOperation::SWAP, 0}, CGateNParams{ControlledGateOperation::IsingXX, 1}, CGateNParams{ControlledGateOperation::IsingXY, 1}, diff --git a/pennylane_lightning/core/src/gates/GateOperation.hpp b/pennylane_lightning/core/src/gates/GateOperation.hpp index 2c8ae16fa6..7764ebea73 100644 --- a/pennylane_lightning/core/src/gates/GateOperation.hpp +++ b/pennylane_lightning/core/src/gates/GateOperation.hpp @@ -82,6 +82,7 @@ enum class ControlledGateOperation : uint32_t { RX, RY, RZ, + Rot, /* Two-qubit gates */ SWAP, IsingXX, 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 b9b9197551..a753a955c2 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 @@ -261,6 +261,9 @@ void assignKernelsForControlledGateOp_Default() { instance.assignKernelForOp(ControlledGateOperation::RZ, all_threading, all_memory_model, all_qubit_numbers, KernelType::LM); + instance.assignKernelForOp(ControlledGateOperation::Rot, all_threading, + all_memory_model, all_qubit_numbers, + KernelType::LM); instance.assignKernelForOp(ControlledGateOperation::SWAP, all_threading, all_memory_model, all_qubit_numbers, diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp index e993603b92..fd4991a7a0 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp @@ -327,6 +327,12 @@ struct ControlledGateOpToMemberFuncPtr; }; template +struct ControlledGateOpToMemberFuncPtr { + constexpr static auto value = + &GateImplementation::template applyNCRot; +}; +template struct ControlledGateOpToMemberFuncPtr { constexpr static auto value = @@ -788,7 +794,8 @@ struct GateFuncPtr { */ template struct ControlledGateFuncPtr { - static_assert(num_params < 2, "The given num_params is not supported."); + static_assert(num_params < 2 || num_params == 3, + "The given num_params is not supported."); }; template struct ControlledGateFuncPtr { @@ -804,6 +811,14 @@ struct ControlledGateFuncPtr { const std::vector &, const std::vector &, bool, ParamT); }; +template +struct ControlledGateFuncPtr { + using Type = void (*)(std::complex *, size_t, + const std::vector &, + const std::vector &, + const std::vector &, bool, ParamT, ParamT, + ParamT); +}; /** * @brief Pointer type for a generator operation @@ -965,6 +980,19 @@ callControlledGateOps(ControlledGateFuncPtrT func, params[0]); } +template +inline void +callControlledGateOps(ControlledGateFuncPtrT func, + std::complex *data, size_t num_qubits, + const std::vector &controlled_wires, + const std::vector &controlled_values, + const std::vector &wires, bool inverse, + const std::vector ¶ms) { + PL_ASSERT(params.size() == 3); + func(data, num_qubits, controlled_wires, controlled_values, wires, inverse, + params[0], params[1], params[2]); +} + /// @} /** * @brief Call a generator operation. 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 58ea7de2ec..fd1f5ea11d 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 @@ -160,6 +160,7 @@ class GateImplementationsLM : public PauliGenerator { ControlledGateOperation::RX, ControlledGateOperation::RY, ControlledGateOperation::RZ, + ControlledGateOperation::Rot, ControlledGateOperation::SWAP, ControlledGateOperation::IsingXX, ControlledGateOperation::IsingXY, @@ -1117,48 +1118,51 @@ class GateImplementationsLM : public PauliGenerator { } template - static void applyRot(std::complex *arr, const size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT phi, ParamT theta, ParamT omega) { + static void + applyNCRot(std::complex *arr, const std::size_t num_qubits, + const std::vector &controlled_wires, + const std::vector &controlled_values, + const std::vector &wires, const bool inverse, + ParamT phi, ParamT theta, ParamT omega) { PL_ASSERT(wires.size() == 1); - const auto rotMat = (inverse) ? getRot(-omega, -theta, -phi) : getRot(phi, theta, omega); + applyNCSingleQubitOp(arr, num_qubits, rotMat.data(), controlled_wires, + controlled_values, wires, inverse); + } + template + static void applyRot(std::complex *arr, + const std::size_t num_qubits, + const std::vector &wires, bool inverse, + ParamT phi, ParamT theta, ParamT omega) { + PL_ASSERT(wires.size() == 1); + const auto rotMat = + (inverse) ? getRot(-omega, -theta, -phi) + : getRot(phi, theta, omega); applySingleQubitOp(arr, num_qubits, rotMat.data(), wires); } template - static void applyCRot(std::complex *arr, size_t num_qubits, - const std::vector &wires, bool inverse, + 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 size_t rev_wire0 = num_qubits - wires[1] - 1; - const size_t rev_wire1 = num_qubits - wires[0] - 1; // Control qubit - - const size_t rev_wire0_shift = static_cast(1U) << rev_wire0; - const size_t rev_wire1_shift = static_cast(1U) << rev_wire1; - - const auto [parity_high, parity_middle, parity_low] = - revWireParity(rev_wire0, rev_wire1); - const auto rotMat = (inverse) ? getRot(-omega, -theta, -phi) : getRot(phi, theta, omega); - PL_LOOP_PARALLEL(1) - for (size_t k = 0; k < exp2(num_qubits - 2); k++) { - const size_t i00 = ((k << 2U) & parity_high) | - ((k << 1U) & parity_middle) | (k & parity_low); - const size_t i10 = i00 | rev_wire1_shift; - const size_t i11 = i00 | rev_wire0_shift | rev_wire1_shift; - + auto core_function = [&rotMat](std::complex *arr, + [[maybe_unused]] const std::size_t i00, + [[maybe_unused]] const std::size_t i01, + const std::size_t i10, + const std::size_t i11) { const std::complex v0 = arr[i10]; const std::complex v1 = arr[i11]; arr[i10] = rotMat[0] * v0 + rotMat[1] * v1; arr[i11] = rotMat[2] * v0 + rotMat[3] * v1; - } + }; + applyNC2( + arr, num_qubits, {}, {}, wires, core_function); } /* Two-qubit gates */ @@ -1812,9 +1816,10 @@ class GateImplementationsLM : public PauliGenerator { /* Multi-qubit gates */ template - static void applyMultiRZ(std::complex *arr, size_t num_qubits, - const std::vector &wires, bool inverse, - ParamT angle) { + static void applyMultiRZ(std::complex *arr, + std::size_t num_qubits, + const std::vector &wires, + bool inverse, ParamT angle) { const std::complex first = std::complex{std::cos(angle / 2), -std::sin(angle / 2)}; const std::complex second = @@ -1823,13 +1828,13 @@ class GateImplementationsLM : public PauliGenerator { (inverse) ? std::conj(first) : first, (inverse) ? std::conj(second) : second}; - size_t wires_parity = 0U; - for (size_t wire : wires) { + std::size_t wires_parity = 0U; + for (std::size_t wire : wires) { wires_parity |= - (static_cast(1U) << (num_qubits - wire - 1)); + (static_cast(1U) << (num_qubits - wire - 1)); } PL_LOOP_PARALLEL(1) - for (size_t k = 0; k < exp2(num_qubits); k++) { + for (std::size_t k = 0; k < exp2(num_qubits); k++) { arr[k] *= shifts[std::popcount(k & wires_parity) % 2]; } } @@ -2543,16 +2548,16 @@ class GateImplementationsLM : public PauliGenerator { template [[nodiscard]] static auto - applyGeneratorMultiRZ(std::complex *arr, size_t num_qubits, - const std::vector &wires, + applyGeneratorMultiRZ(std::complex *arr, std::size_t num_qubits, + const std::vector &wires, [[maybe_unused]] bool adj) -> PrecisionT { - auto wires_parity = static_cast(0U); - for (size_t wire : wires) { + auto wires_parity = static_cast(0U); + for (std::size_t wire : wires) { wires_parity |= - (static_cast(1U) << (num_qubits - wire - 1)); + (static_cast(1U) << (num_qubits - wire - 1)); } PL_LOOP_PARALLEL(1) - for (size_t k = 0; k < exp2(num_qubits); k++) { + for (std::size_t k = 0; k < exp2(num_qubits); k++) { arr[k] *= static_cast( 1 - 2 * int(std::popcount(k & wires_parity) % 2)); } @@ -2562,31 +2567,32 @@ class GateImplementationsLM : public PauliGenerator { template [[nodiscard]] static auto - applyNCGeneratorMultiRZ(std::complex *arr, size_t num_qubits, - const std::vector &controlled_wires, + applyNCGeneratorMultiRZ(std::complex *arr, + std::size_t num_qubits, + const std::vector &controlled_wires, const std::vector &controlled_values, - const std::vector &wires, + const std::vector &wires, [[maybe_unused]] bool adj) -> PrecisionT { PL_ABORT_IF_NOT(controlled_wires.size() == controlled_values.size(), "`controlled_wires` must have the same size as " "`controlled_values`."); - constexpr size_t one{1}; + constexpr std::size_t one{1}; constexpr std::complex zero{0.0}; - auto ctrls_mask = static_cast(0U); - for (size_t i = 0; i < controlled_wires.size(); i++) { - ctrls_mask |= (static_cast(controlled_values[i]) + auto ctrls_mask = static_cast(0U); + for (std::size_t i = 0; i < controlled_wires.size(); i++) { + ctrls_mask |= (static_cast(controlled_values[i]) << (num_qubits - controlled_wires[i] - 1)); } - auto ctrls_parity = static_cast(0U); - for (size_t i = 0; i < controlled_wires.size(); i++) { - ctrls_parity |= (one << (num_qubits - controlled_wires[i] - 1)); + auto ctrls_parity = static_cast(0U); + for (std::size_t wire : controlled_wires) { + ctrls_parity |= (one << (num_qubits - wire - 1)); } - auto wires_parity = static_cast(0U); - for (size_t wire : wires) { + auto wires_parity = static_cast(0U); + for (std::size_t wire : wires) { wires_parity |= (one << (num_qubits - wire - 1)); } PL_LOOP_PARALLEL(1) - for (size_t k = 0; k < exp2(num_qubits); k++) { + for (std::size_t k = 0; k < exp2(num_qubits); k++) { if (ctrls_mask == (ctrls_parity & k)) { arr[k] *= static_cast( 1 - 2 * int(std::popcount(k & wires_parity) % 2)); diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.py b/pennylane_lightning/lightning_qubit/lightning_qubit.py index ddd6764d79..fb7c75f5a6 100644 --- a/pennylane_lightning/lightning_qubit/lightning_qubit.py +++ b/pennylane_lightning/lightning_qubit/lightning_qubit.py @@ -132,6 +132,7 @@ def _state_dtype(dtype): "C(RX)", "C(RY)", "C(RZ)", + "C(Rot)", "C(SWAP)", "C(IsingXX)", "C(IsingXY)", diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py index 4cf59ec6cd..d1381d4856 100644 --- a/tests/test_adjoint_jacobian.py +++ b/tests/test_adjoint_jacobian.py @@ -705,6 +705,7 @@ def circuit(x, y, z): qml.RX, qml.RY, qml.RZ, + qml.Rot, qml.IsingXX, qml.IsingXY, qml.IsingYY, @@ -738,15 +739,24 @@ def test_controlled_jacobian(self, par, n_qubits, control_value, operation, tol) def circuit(p): qml.StatePrep(init_state, wires=range(n_qubits)) - qml.RX(p[0], 0) - qml.ctrl( - operation(p[1], wires=range(n_qubits - num_wires, n_qubits)), - control_wires, - control_values=[ - control_value or bool(i % 2) for i, _ in enumerate(control_wires) - ], - ) - qml.RY(p[2], 0) + if operation.num_params == 3: + qml.ctrl( + operation(*p, wires=range(n_qubits - num_wires, n_qubits)), + control_wires, + control_values=[ + control_value or bool(i % 2) for i, _ in enumerate(control_wires) + ], + ) + else: + qml.RX(p[0], 0) + qml.ctrl( + operation(p[1], wires=range(n_qubits - num_wires, n_qubits)), + control_wires, + control_values=[ + control_value or bool(i % 2) for i, _ in enumerate(control_wires) + ], + ) + qml.RY(p[2], 0) return np.array([qml.expval(qml.PauliY(i)) for i in range(n_qubits)]) circ_ad = qml.QNode(circuit, dev, diff_method="adjoint") diff --git a/tests/test_gates.py b/tests/test_gates.py index f5a11bd152..68f771af90 100644 --- a/tests/test_gates.py +++ b/tests/test_gates.py @@ -351,6 +351,7 @@ def circuit(): qml.RX, qml.RY, qml.RZ, + qml.Rot, qml.SWAP, qml.IsingXX, qml.IsingXY, @@ -396,7 +397,7 @@ def circuit(): ) else: qml.ctrl( - operation(0.1234, target_wires), + operation(*tuple([0.1234] * operation.num_params), target_wires), control_wires, control_values=[ control_value or bool(i % 2) for i, _ in enumerate(control_wires) From 2a8fea5f09ddae1f0ea23e873bdd41a9cdfba817 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Tue, 13 Feb 2024 18:11:14 +0000 Subject: [PATCH 05/16] Update changelog. --- .github/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index bc36e8a477..b30b92c0c0 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -12,6 +12,9 @@ ### Improvements +* `C(MultiRZ)` and `C(Rot)` gates are natively supported (with `LM` kernels). + [(#614)](https://github.com/PennyLaneAI/pennylane-lightning/pull/614) + * Lower the overheads of Windows CI tests. [(#610)](https://github.com/PennyLaneAI/pennylane-lightning/pull/610) From 4ed8c1acafba8c5f2ced77b81d65fc5ec03f7b00 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Tue, 13 Feb 2024 19:14:26 +0000 Subject: [PATCH 06/16] AddC++ tests for C(Rot/MultiRZ). --- .../cpu_kernels/GateImplementationsLM.hpp | 4 +- .../tests/Test_GateImplementations_Param.cpp | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) 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 fd1f5ea11d..ab7e60ba8f 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 @@ -1125,9 +1125,7 @@ class GateImplementationsLM : public PauliGenerator { const std::vector &wires, const bool inverse, ParamT phi, ParamT theta, ParamT omega) { PL_ASSERT(wires.size() == 1); - const auto rotMat = - (inverse) ? getRot(-omega, -theta, -phi) - : getRot(phi, theta, omega); + const auto rotMat = getRot(phi, theta, omega); applyNCSingleQubitOp(arr, num_qubits, rotMat.data(), controlled_wires, controlled_values, wires, inverse); } diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_GateImplementations_Param.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_GateImplementations_Param.cpp index 1726804fbe..21ac2ed932 100644 --- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_GateImplementations_Param.cpp +++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_GateImplementations_Param.cpp @@ -2356,6 +2356,28 @@ TEMPLATE_TEST_CASE( approx(sv1.getDataVector()).margin(margin)); } } + + DYNAMIC_SECTION("N-controlled Rot - " + << "controls = {" << control << "} " + << ", wires = {" << wire << "} - " + << PrecisionToName::value) { + const bool inverse = GENERATE(false, true); + const PrecisionT param = GENERATE(-1.5, -0.5, 0, 0.5, 1.5); + if (control != wire) { + auto st0 = createRandomStateVectorData(re, num_qubits); + sv0.updateData(st0); + sv1.updateData(st0); + const std::vector params = { + param, static_cast(2.0) * param, + static_cast(3.0) * param}; + sv0.applyOperation("CRot", {control, wire}, inverse, params); + sv1.applyOperation("Rot", std::vector{control}, + std::vector{true}, + std::vector{wire}, inverse, params); + REQUIRE(sv0.getDataVector() == + approx(sv1.getDataVector()).margin(margin)); + } + } } TEMPLATE_TEST_CASE( @@ -2662,4 +2684,35 @@ TEMPLATE_TEST_CASE( approx(sv1.getDataVector()).margin(margin)); } } + + DYNAMIC_SECTION("N-controlled MultiRZ - " + << "controls = {" << control << ", " << wire0 << ", " + << wire1 << "} " + << ", wires = {" << wire2 << ", " << wire3 << "} - " + << PrecisionToName::value) { + bool inverse = GENERATE(false, true); + PrecisionT param = GENERATE(-1.5, -0.5, 0, 0.5, 1.5); + std::vector wires = {control, wire0, wire1, wire2, wire3}; + std::sort(wires.begin(), wires.end()); + const ComplexT e = std::exp(ComplexT{0, -0.5} * param); + std::vector matrix(16, 0.0); + matrix[0] = e; + matrix[5] = std::conj(e); + matrix[10] = std::conj(e); + matrix[15] = e; + if (std::adjacent_find(wires.begin(), wires.end()) == wires.end()) { + auto st0 = createRandomStateVectorData(re, num_qubits); + sv0.updateData(st0); + sv1.updateData(st0); + sv0.applyControlledMatrix(matrix.data(), {control, wire0, wire1}, + std::vector{true, false, true}, + {wire2, wire3}, inverse); + sv1.applyOperation( + "MultiRZ", std::vector{control, wire0, wire1}, + std::vector{true, false, true}, + std::vector{wire2, wire3}, inverse, {param}); + REQUIRE(sv0.getDataVector() == + approx(sv1.getDataVector()).margin(margin)); + } + } } \ No newline at end of file From 878044b78b04743ac432c363e9fee823891cad0c Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Tue, 13 Feb 2024 20:35:49 +0000 Subject: [PATCH 07/16] Fix tidy warning. --- .../gates/cpu_kernels/GateImplementationsLM.hpp | 7 ++----- tests/test_adjoint_jacobian.py | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) 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 ab7e60ba8f..323f8b0181 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 @@ -1844,9 +1844,6 @@ class GateImplementationsLM : public PauliGenerator { const std::vector &controlled_values, const std::vector &wires, bool inverse, ParamT angle) { - static constexpr std::size_t one{1}; - const std::size_t dim = one << wires.size(); - const std::complex first = std::complex{std::cos(angle / 2), -std::sin(angle / 2)}; const std::complex second = @@ -1860,12 +1857,12 @@ class GateImplementationsLM : public PauliGenerator { (static_cast(1U) << (num_qubits - wire - 1)); } auto core_function = - [dim, wires_parity, &shifts]( + [wires_parity, &shifts]( std::complex *arr, const std::vector &indices, [[maybe_unused]] const std::vector> &coeffs_in) { - for (auto &k : indices) { + for (const auto &k : indices) { arr[k] *= shifts[std::popcount(k & wires_parity) % 2]; } }; diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py index d1381d4856..5617525f76 100644 --- a/tests/test_adjoint_jacobian.py +++ b/tests/test_adjoint_jacobian.py @@ -705,7 +705,6 @@ def circuit(x, y, z): qml.RX, qml.RY, qml.RZ, - qml.Rot, qml.IsingXX, qml.IsingXY, qml.IsingYY, From 0d07a77b1d2886e5794ac719ecea692416e9bead Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Wed, 14 Feb 2024 14:22:21 +0000 Subject: [PATCH 08/16] Auto update version --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index af34c02f2a..2c10c62ab0 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.35.0-dev14" +__version__ = "0.35.0-dev15" From 00aaa927d73d6eab6813c3cb12ad1755ac7641fa Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Wed, 14 Feb 2024 20:32:27 +0000 Subject: [PATCH 09/16] trigger ci From 21399e5eb0e8870f3f99046bfb59f434d72e655d Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Thu, 15 Feb 2024 21:54:27 +0000 Subject: [PATCH 10/16] Auto update version --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index 2c10c62ab0..a223e801fa 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.35.0-dev15" +__version__ = "0.35.0-dev16" From 2665db0e693cbe8ab60e1ff958c4ae99aa2e6f5d Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Thu, 15 Feb 2024 21:59:49 +0000 Subject: [PATCH 11/16] trigger ci From 0ee3d14e1be237e2ea63d99fd948d458552bb1ec Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Thu, 15 Feb 2024 21:59:59 +0000 Subject: [PATCH 12/16] trigger ci From 8fd726b11cf7a697624b8a03821a12dbca120314 Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Mon, 19 Feb 2024 14:05:41 +0000 Subject: [PATCH 13/16] Add C(Rot) adjoint tests. --- tests/test_adjoint_jacobian.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py index 442b293179..58f6bf2945 100644 --- a/tests/test_adjoint_jacobian.py +++ b/tests/test_adjoint_jacobian.py @@ -705,6 +705,7 @@ def circuit(x, y, z): qml.RX, qml.RY, qml.RZ, + qml.Rot, qml.IsingXX, qml.IsingXY, qml.IsingYY, From be529aa012e333a749daed13ed593d0b955a25d1 Mon Sep 17 00:00:00 2001 From: Dev version update bot Date: Thu, 22 Feb 2024 15:13:09 +0000 Subject: [PATCH 14/16] Auto update version --- pennylane_lightning/core/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane_lightning/core/_version.py b/pennylane_lightning/core/_version.py index a223e801fa..92ab0f4480 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.35.0-dev16" +__version__ = "0.35.0-dev17" From ea94d18d18e57df821f906f6e17ac8dc98a4099c Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Thu, 22 Feb 2024 10:13:37 -0500 Subject: [PATCH 15/16] trigger ci From d22d0763cc4c7a5e5bc6647d602025228b5b80ad Mon Sep 17 00:00:00 2001 From: Vincent Michaud-Rioux Date: Thu, 22 Feb 2024 10:47:34 -0500 Subject: [PATCH 16/16] Test gate/controls against DQ+backprop. --- tests/test_adjoint_jacobian.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py index 4ba8c861cf..eaf6aa59eb 100644 --- a/tests/test_adjoint_jacobian.py +++ b/tests/test_adjoint_jacobian.py @@ -722,9 +722,10 @@ def circuit(x, y, z): @pytest.mark.parametrize("n_qubits", range(2, 6)) @pytest.mark.parametrize("par", [-np.pi / 7, np.pi / 5, 2 * np.pi / 3]) def test_gate_jacobian(self, par, n_qubits, operation, tol): - """Test that the jacobian of the controlled gate matches the finite-diff formula.""" + """Test that the jacobian of the controlled gate matches backprop.""" par = np.array([0.1234, par, 0.5678]) dev = qml.device(device_name, wires=n_qubits) + dqu = qml.device("default.qubit", wires=n_qubits) np.random.seed(1337) init_state = np.random.rand(2**n_qubits) + 1.0j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) @@ -747,15 +748,15 @@ def circuit(p): return np.array([qml.expval(qml.PauliY(i)) for i in range(n_qubits)]) circ_ad = qml.QNode(circuit, dev, diff_method="adjoint") - circ_ps = qml.QNode(circuit, dev, diff_method="finite-diff") + circ_bp = qml.QNode(circuit, dqu, diff_method="backprop") jac_ad = np.array(qml.jacobian(circ_ad)(par)) - jac_ps = np.array(qml.jacobian(circ_ps)(par)) + jac_bp = np.array(qml.jacobian(circ_bp)(par)) # different methods must agree assert jac_ad.size == n_qubits * 3 assert np.allclose(jac_ad.shape, [n_qubits, 3]) - assert np.allclose(jac_ad.shape, jac_ps.shape) - assert np.allclose(jac_ad, jac_ps, atol=tol, rtol=0) + assert np.allclose(jac_ad.shape, jac_bp.shape) + assert np.allclose(jac_ad, jac_bp, atol=tol, rtol=0) @pytest.mark.skipif( device_name != "lightning.qubit" or not ld._CPP_BINARY_AVAILABLE, @@ -790,6 +791,7 @@ def test_controlled_jacobian(self, par, n_qubits, control_value, operation, tol) """Test that the jacobian of the controlled gate matches the parameter-shift formula.""" par = np.array([0.1234, par, 0.5678]) dev = qml.device("lightning.qubit", wires=n_qubits) + dqu = qml.device("default.qubit", wires=n_qubits) np.random.seed(1337) init_state = np.random.rand(2**n_qubits) + 1.0j * np.random.rand(2**n_qubits) init_state /= np.sqrt(np.dot(np.conj(init_state), init_state)) @@ -824,15 +826,15 @@ def circuit(p): return np.array([qml.expval(qml.PauliY(i)) for i in range(n_qubits)]) circ_ad = qml.QNode(circuit, dev, diff_method="adjoint") - circ_ps = qml.QNode(circuit, dev, diff_method="parameter-shift") + circ_bp = qml.QNode(circuit, dqu, diff_method="backprop") jac_ad = np.array(qml.jacobian(circ_ad)(par)) - jac_ps = np.array(qml.jacobian(circ_ps)(par)) + jac_bp = np.array(qml.jacobian(circ_bp)(par)) # different methods must agree assert jac_ad.size == n_qubits * 3 assert np.allclose(jac_ad.shape, [n_qubits, 3]) - assert np.allclose(jac_ad.shape, jac_ps.shape) - assert np.allclose(jac_ad, jac_ps, atol=tol, rtol=0) + assert np.allclose(jac_ad.shape, jac_bp.shape) + assert np.allclose(jac_ad, jac_bp, atol=tol, rtol=0) thetas = np.linspace(-2 * np.pi, 2 * np.pi, 8)