Repository: PennyLaneAI/pennylane-lightning
Pull request #1093: Implement Generators for PSWAP gate
Author: login: jzaia18
Labels: name: ci:use-multi-gpu-runner
description: Enable usage of Multi-GPU runner for this Pull Request
name: ci:build_wheels
description: Activate wheel building.
name: ci:use-gpu-runner
description: Enable usage of GPU runner for this Pull Request
Created: 2025-03-14T20:56:57Z | Merged: 2025-03-21T15:16:47Z

**Context:**
Currently, the implementation of PSWAP does not contain its generators, and the gate is not differentiable.

**Description of the Change:**
Implements generators for the PSWAP gate.

**Benefits:**

**Possible Drawbacks:**

**Related GitHub Issues:**
[sc-86524]


Diff:
diff --git a/pennylane_lightning/core/src/gates/Constant.hpp b/pennylane_lightning/core/src/gates/Constant.hpp
index e03e5fa177..c0af62e4c3 100644
--- a/pennylane_lightning/core/src/gates/Constant.hpp
+++ b/pennylane_lightning/core/src/gates/Constant.hpp
@@ -153,6 +153,7 @@ using GeneratorView = typename std::pair<GeneratorOperation, std::string_view>;
     GeneratorView{GeneratorOperation::DoubleExcitationPlus,
                   "DoubleExcitationPlus"},
     GeneratorView{GeneratorOperation::GlobalPhase, "GlobalPhase"},
+    GeneratorView{GeneratorOperation::PSWAP, "PSWAP"},
 };
 
 using CGeneratorView =
@@ -180,6 +181,7 @@ using CGeneratorView =
                    "DoubleExcitationPlus"},
     CGeneratorView{ControlledGeneratorOperation::MultiRZ, "MultiRZ"},
     CGeneratorView{ControlledGeneratorOperation::GlobalPhase, "GlobalPhase"},
+    CGeneratorView{ControlledGeneratorOperation::PSWAP, "PSWAP"},
 };
 
 /**
@@ -296,6 +298,7 @@ using GeneratorNWires = typename std::pair<GeneratorOperation, std::size_t>;
     GeneratorNWires{GeneratorOperation::DoubleExcitationMinus, 4},
     GeneratorNWires{GeneratorOperation::DoubleExcitationPlus, 4},
     GeneratorNWires{GeneratorOperation::GlobalPhase, 1},
+    GeneratorNWires{GeneratorOperation::PSWAP, 1},
 };
 
 using CGeneratorNWires =
@@ -316,6 +319,7 @@ using CGeneratorNWires =
     CGeneratorNWires{ControlledGeneratorOperation::DoubleExcitationMinus, 4},
     CGeneratorNWires{ControlledGeneratorOperation::DoubleExcitationPlus, 4},
     CGeneratorNWires{ControlledGeneratorOperation::GlobalPhase, 1},
+    CGeneratorNWires{ControlledGeneratorOperation::PSWAP, 1},
 };
 
 /**
diff --git a/pennylane_lightning/core/src/gates/GateOperation.hpp b/pennylane_lightning/core/src/gates/GateOperation.hpp
index 31259109ba..a52c593bd2 100644
--- a/pennylane_lightning/core/src/gates/GateOperation.hpp
+++ b/pennylane_lightning/core/src/gates/GateOperation.hpp
@@ -131,6 +131,7 @@ enum class GeneratorOperation : uint32_t {
     DoubleExcitation,
     DoubleExcitationMinus,
     DoubleExcitationPlus,
+    PSWAP,
     MultiRZ,
     GlobalPhase,
     /* END (placeholder) */
@@ -153,6 +154,7 @@ enum class ControlledGeneratorOperation : uint32_t {
     DoubleExcitation,
     DoubleExcitationMinus,
     DoubleExcitationPlus,
+    PSWAP,
     MultiRZ,
     GlobalPhase,
     /* END (placeholder) */
diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp
index dc535b89d9..09a77fb1dd 100644
--- a/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp
+++ b/pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp
@@ -1203,6 +1203,25 @@ class StateVectorCudaManaged
         return -static_cast<PrecisionT>(0.5);
     }
 
+    /**
+     * @brief Gradient generator function associated with the PSWAP gate.
+     *
+     * @param wires Wires to apply operation.
+     * @param adj Takes adjoint of operation if true. Defaults to false.
+     */
+    inline PrecisionT applyGeneratorPSWAP(const std::vector<std::size_t> &wires,
+                                          bool adj = false) {
+        static const std::string name{"GeneratorPSWAP"};
+        static const Precision param = 0.0;
+        const auto gate_key = std::make_pair(name, param);
+        if (!gate_cache_.gateExists(gate_key)) {
+            gate_cache_.add_gate(gate_key, cuGates::getGeneratorPSWAP<CFP_t>());
+        }
+        applyDeviceMatrixGate_(gate_cache_.get_gate_device_ptr(gate_key), {},
+                               wires, adj);
+        return static_cast<PrecisionT>(1.0);
+    }
+
     /* Controlled-gate generators */
     /**
      * @brief Gradient generator function associated with the controlled-RX
@@ -1715,6 +1734,38 @@ class StateVectorCudaManaged
         return -static_cast<PrecisionT>(1.0);
     }
 
+    inline PrecisionT applyControlledGeneratorPSWAP(
+        const std::vector<std::size_t> &controlled_wires,
+        const std::vector<bool> &controlled_values,
+        const std::vector<std::size_t> &wires, bool adj = false) {
+        const std::size_t ctrl_size = controlled_wires.size();
+        const std::size_t tgt_size = wires.size();
+
+        // Generate permutation
+        std::vector<custatevecIndex_t> permutations =
+            generateTrivialPermutation(ctrl_size, tgt_size);
+        std::size_t index = controlPermutationMatrixIndex(ctrl_size, tgt_size,
+                                                          controlled_values);
+        std::swap(permutations[index + 1], permutations[index + 2]);
+
+        // Generate diagonals
+        std::vector<CFP_t> diagonals(permutations.size(),
+                                     cuUtil::ZERO<CFP_t>());
+        diagonals[index + 1] = cuUtil::ONE<CFP_t>();
+        diagonals[index + 2] = cuUtil::ONE<CFP_t>();
+
+        std::vector<std::size_t> combined_tgts(ctrl_size + tgt_size);
+        std::copy(controlled_wires.begin(), controlled_wires.end(),
+                  combined_tgts.begin());
+        std::copy(wires.begin(), wires.end(),
+                  combined_tgts.begin() + ctrl_size);
+
+        applyDevicePermutationGate_(permutations, diagonals.data(), {},
+                                    combined_tgts, {}, adj);
+
+        return static_cast<PrecisionT>(1.0);
+    }
+
     inline PrecisionT applyControlledGeneratorMultiRZ(
         const std::vector<std::size_t> &controlled_wires,
         const std::vector<bool> &controlled_values,
@@ -1958,6 +2009,12 @@ class StateVectorCudaManaged
 
     // Holds the mapping from gate labels to associated generator functions.
     const GMap generator_map_{
+        {"PSWAP",
+         [&](auto &&wires, auto &&adjoint) {
+             return applyGeneratorPSWAP(
+                 std::forward<decltype(wires)>(wires),
+                 std::forward<decltype(adjoint)>(adjoint));
+         }},
         {"GlobalPhase",
          [&](auto &&wires, auto &&adjoint) {
              return applyGeneratorGlobalPhase(
@@ -2135,7 +2192,9 @@ class StateVectorCudaManaged
              &StateVectorCudaManaged::applyControlledGeneratorGlobalPhase)},
         {"MultiRZ",
          makeControlledGenerator(
-             &StateVectorCudaManaged::applyControlledGeneratorMultiRZ)}};
+             &StateVectorCudaManaged::applyControlledGeneratorMultiRZ)},
+        {"PSWAP", makeControlledGenerator(
+                      &StateVectorCudaManaged::applyControlledGeneratorPSWAP)}};
 
     /**
      * @brief Normalize the index ordering to match PennyLane.
diff --git a/pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp b/pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp
index f3b6e8a601..3387f9bb90 100644
--- a/pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp
+++ b/pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp
@@ -160,6 +160,42 @@ TEST_CASE("Generators::applyGeneratorPhaseShift", "[GateGenerators]") {
     }
 }
 
+TEST_CASE("Generators::applyGeneratorPSWAP", "[GateGenerators]") {
+    std::vector<typename StateVectorCudaManaged<double>::CFP_t> matrix{
+        {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0},
+        {1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0},
+        {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0},
+    };
+    std::mt19937 re{1337U};
+
+    for (std::size_t num_qubits = 1; num_qubits <= 5; num_qubits++) {
+        for (std::size_t applied_qubit = 0; applied_qubit < num_qubits;
+             applied_qubit++) {
+            auto init_state =
+                createRandomStateVectorData<double>(re, num_qubits);
+
+            StateVectorCudaManaged<double> psi(init_state.data(),
+                                               init_state.size());
+            StateVectorCudaManaged<double> psi_direct(init_state.data(),
+                                                      init_state.size());
+            StateVectorCudaManaged<double> psi_dispatch(init_state.data(),
+                                                        init_state.size());
+
+            std::string cache_gate_name = "DirectGenPSWAP" +
+                                          std::to_string(applied_qubit) + "_" +
+                                          std::to_string(num_qubits);
+
+            psi.applyGeneratorPSWAP({applied_qubit}, false);
+            psi_direct.applyOperation(cache_gate_name, {applied_qubit}, false,
+                                      {0.0}, matrix);
+            psi_dispatch.applyGenerator({"PSWAP"}, {applied_qubit}, false);
+
+            CHECK(psi.getDataVector() == psi_direct.getDataVector());
+            CHECK(psi_dispatch.getDataVector() == psi_direct.getDataVector());
+        }
+    }
+}
+
 TEST_CASE("Generators::applyGeneratorIsingXX", "[GateGenerators]") {
     // grad(IsingXX)() = e^{-i*0.5*a*(kron(X, X))}) => -0.5*i*(kron(X, X))
     std::vector<typename StateVectorCudaManaged<double>::CFP_t> matrix{
@@ -1770,7 +1806,7 @@ TEMPLATE_TEST_CASE("Generators::applyControlledGenerator - 2 wires",
     const std::string controlled_gate_name =
         GENERATE("IsingXX", "IsingXY", "IsingYY", "IsingZZ", "SingleExcitation",
                  "SingleExcitationMinus", "SingleExcitationPlus", "GlobalPhase",
-                 "MultiRZ");
+                 "MultiRZ", "PSWAP");
     const std::size_t num_qubits = 4;
     const TestType ep_deriv = 1e-3;
     const TestType ep_margin = 1e-4;
diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/gates/BasicGeneratorFunctors.hpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/gates/BasicGeneratorFunctors.hpp
index 6b25fdb524..8f88e0a74a 100644
--- a/pennylane_lightning/core/src/simulators/lightning_kokkos/gates/BasicGeneratorFunctors.hpp
+++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/gates/BasicGeneratorFunctors.hpp
@@ -234,6 +234,22 @@ void applyGenSingleExcitationPlus(
         ExecutionSpace{}, arr_, num_qubits, wires, core_function);
 }
 
+template <class ExecutionSpace, class PrecisionT>
+void applyGenPSWAP(Kokkos::View<Kokkos::complex<PrecisionT> *> arr_,
+                   std::size_t num_qubits,
+                   const std::vector<std::size_t> &wires,
+                   [[maybe_unused]] bool inverse = false) {
+    auto core_function = KOKKOS_LAMBDA(
+        Kokkos::View<Kokkos::complex<PrecisionT> *> arr, std::size_t i00,
+        std::size_t i01, std::size_t i10, std::size_t i11) {
+        arr(i00) = 0.0;
+        arr(i11) = 0.0;
+        kokkos_swap(arr(i01), arr(i10));
+    };
+    applyNC2Functor<PrecisionT, decltype(core_function), false>(
+        ExecutionSpace{}, arr_, num_qubits, wires, core_function);
+}
+
 template <class ExecutionSpace, class PrecisionT>
 void applyGenDoubleExcitation(Kokkos::View<Kokkos::complex<PrecisionT> *> arr_,
                               std::size_t num_qubits,
@@ -749,6 +765,25 @@ void applyNCGenSingleExcitationPlus(
         wires, core_function);
 }
 
+template <class ExecutionSpace, class PrecisionT>
+void applyNCGenPSWAP(Kokkos::View<Kokkos::complex<PrecisionT> *> arr_,
+                     std::size_t num_qubits,
+                     const std::vector<std::size_t> &controlled_wires,
+                     const std::vector<bool> &controlled_values,
+                     const std::vector<std::size_t> &wires,
+                     [[maybe_unused]] bool inverse = false) {
+    auto core_function = KOKKOS_LAMBDA(
+        Kokkos::View<Kokkos::complex<PrecisionT> *> arr, std::size_t i00,
+        std::size_t i01, std::size_t i10, std::size_t i11) {
+        arr(i00) = 0.0;
+        arr(i11) = 0.0;
+        kokkos_swap(arr(i01), arr(i10));
+    };
+    applyNCGenerator2Functor<PrecisionT, decltype(core_function)>(
+        ExecutionSpace{}, arr_, num_qubits, controlled_wires, controlled_values,
+        wires, core_function);
+}
+
 template <class PrecisionT, class FuncT> class applyNCGenerator4Functor {
     using KokkosIntVector = Kokkos::View<std::size_t *>;
 
@@ -999,6 +1034,9 @@ PrecisionT applyNamedGenerator(const GeneratorOperation generator_op,
         return -static_cast<PrecisionT>(0.5);
     case GeneratorOperation::GlobalPhase:
         return static_cast<PrecisionT>(-1.0);
+    case GeneratorOperation::PSWAP:
+        applyGenPSWAP<ExecutionSpace>(arr_, num_qubits, wires, inverse);
+        return static_cast<PrecisionT>(1.0);
     default:
         PL_ABORT("Generator operation does not exist.");
     }
@@ -1083,6 +1121,10 @@ PrecisionT applyNCNamedGenerator(
             arr_, num_qubits, controlled_wires, controlled_values, wires,
             inverse);
         return static_cast<PrecisionT>(-1.0);
+    case ControlledGeneratorOperation::PSWAP:
+        applyNCGenPSWAP<ExecutionSpace>(arr_, num_qubits, controlled_wires,
+                                        controlled_values, wires, inverse);
+        return static_cast<PrecisionT>(1.0);
     default:
         PL_ABORT("Controlled generator operation does not exist.");
     }
diff --git a/pennylane_lightning/core/src/simulators/lightning_kokkos/gates/tests/Test_StateVectorKokkos_Generator.cpp b/pennylane_lightning/core/src/simulators/lightning_kokkos/gates/tests/Test_StateVectorKokkos_Generator.cpp
index 87baa45ceb..beb1734ac6 100644
--- a/pennylane_lightning/core/src/simulators/lightning_kokkos/gates/tests/Test_StateVectorKokkos_Generator.cpp
+++ b/pennylane_lightning/core/src/simulators/lightning_kokkos/gates/tests/Test_StateVectorKokkos_Generator.cpp
@@ -124,7 +124,7 @@ TEMPLATE_TEST_CASE("StateVectorKokkos::applyGenerator",
         "CRZ", "IsingXX", "IsingXY", "IsingYY", "IsingZZ", "SingleExcitation",
         "SingleExcitationMinus", "SingleExcitationPlus", "DoubleExcitation",
         "DoubleExcitationMinus", "DoubleExcitationPlus", "MultiRZ",
-        "GlobalPhase");
+        "GlobalPhase", "PSWAP");
     DYNAMIC_SECTION("Generator - Gate = " << gate_name
                                           << " Inverse = " << inverse) {
         StateVectorKokkos<TestType> kokkos_gntr_sv{ini_st.data(),
@@ -456,7 +456,7 @@ TEMPLATE_TEST_CASE("StateVectorKokkos::applyControlledGenerator",
         "RX", "RY", "RZ", "PhaseShift", "GlobalPhase", "IsingXX", "IsingXY",
         "IsingYY", "IsingZZ", "SingleExcitation", "SingleExcitationMinus",
         "SingleExcitationPlus", "DoubleExcitation", "DoubleExcitationMinus",
-        "DoubleExcitationPlus", "MultiRZ");
+        "DoubleExcitationPlus", "MultiRZ", "PSWAP");
 
     DYNAMIC_SECTION("Matrix - Gate = " << controlled_gate_name << " Inverse = "
                                        << inverse << " 1-control: c{5}") {
@@ -654,7 +654,7 @@ TEMPLATE_TEST_CASE("StateVectorKokkos::applyControlledGenerator empty control",
 
     const bool inverse = GENERATE(true, false);
     const std::string controlled_gate_name =
-        GENERATE("RX", "RY", "RZ", "PhaseShift", "GlobalPhase");
+        GENERATE("RX", "RY", "RZ", "PhaseShift", "GlobalPhase", "PSWAP");
     {
         StateVectorKokkos<TestType> kokkos_gntr_sv{ini_st.data(),
                                                    ini_st.size()};
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 b9e52bff94..39379b1f5e 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
@@ -120,6 +120,9 @@ void assignKernelsForGateOp_Default() {
     instance.assignKernelForOp(GateOperation::CRot, all_threading,
                                all_memory_model, all_qubit_numbers,
                                KernelType::LM);
+    instance.assignKernelForOp(GateOperation::PSWAP, all_threading,
+                               all_memory_model, all_qubit_numbers,
+                               KernelType::LM);
 
     /* Three-qubit gates */
     instance.assignKernelForOp(GateOperation::Toffoli, all_threading,
@@ -156,9 +159,6 @@ void assignKernelsForGateOp_Default() {
     instance.assignKernelForOp(GateOperation::GlobalPhase, all_threading,
                                all_memory_model, all_qubit_numbers,
                                KernelType::LM);
-    instance.assignKernelForOp(GateOperation::PSWAP, all_threading,
-                               all_memory_model, all_qubit_numbers,
-                               KernelType::LM);
 }
 
 void assignKernelsForGeneratorOp_Default() {
@@ -200,6 +200,9 @@ void assignKernelsForGeneratorOp_Default() {
     instance.assignKernelForOp(GeneratorOperation::ControlledPhaseShift,
                                all_threading, all_memory_model,
                                all_qubit_numbers, KernelType::LM);
+    instance.assignKernelForOp(GeneratorOperation::PSWAP, all_threading,
+                               all_memory_model, all_qubit_numbers,
+                               KernelType::LM);
 
     instance.assignKernelForOp(GeneratorOperation::SingleExcitation,
                                all_threading, all_memory_model,
@@ -294,6 +297,9 @@ void assignKernelsForControlledGateOp_Default() {
     instance.assignKernelForOp(ControlledGateOperation::IsingZZ, all_threading,
                                all_memory_model, all_qubit_numbers,
                                KernelType::LM);
+    instance.assignKernelForOp(ControlledGateOperation::PSWAP, all_threading,
+                               all_memory_model, all_qubit_numbers,
+                               KernelType::LM);
     instance.assignKernelForOp(ControlledGateOperation::SingleExcitation,
                                all_threading, all_memory_model,
                                all_qubit_numbers, KernelType::LM);
@@ -319,9 +325,6 @@ void assignKernelsForControlledGateOp_Default() {
     instance.assignKernelForOp(ControlledGateOperation::GlobalPhase,
                                all_threading, all_memory_model,
                                all_qubit_numbers, KernelType::LM);
-    instance.assignKernelForOp(ControlledGateOperation::PSWAP, all_threading,
-                               all_memory_model, all_qubit_numbers,
-                               KernelType::LM);
 }
 void assignKernelsForControlledGeneratorOp_Default() {
     auto &instance =
@@ -351,6 +354,9 @@ void assignKernelsForControlledGeneratorOp_Default() {
     instance.assignKernelForOp(ControlledGeneratorOperation::IsingZZ,
                                all_threading, all_memory_model,
                                all_qubit_numbers, KernelType::LM);
+    instance.assignKernelForOp(ControlledGeneratorOperation::PSWAP,
+                               all_threading, all_memory_model,
+                               all_qubit_numbers, KernelType::LM);
     instance.assignKernelForOp(ControlledGeneratorOperation::SingleExcitation,
                                all_threading, all_memory_model,
                                all_qubit_numbers, KernelType::LM);
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 d09e590ca0..93efa7204d 100644
--- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp
+++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/OpToMemberFuncPtr.hpp
@@ -584,6 +584,12 @@ struct GeneratorOpToMemberFuncPtr<PrecisionT, GateImplementation,
             PrecisionT>;
 };
 template <class PrecisionT, class GateImplementation>
+struct GeneratorOpToMemberFuncPtr<PrecisionT, GateImplementation,
+                                  GeneratorOperation::PSWAP> {
+    constexpr static auto value =
+        &GateImplementation::template applyGeneratorPSWAP<PrecisionT>;
+};
+template <class PrecisionT, class GateImplementation>
 struct GeneratorOpToMemberFuncPtr<PrecisionT, GateImplementation,
                                   GeneratorOperation::MultiRZ> {
     constexpr static auto value =
@@ -699,6 +705,12 @@ struct ControlledGeneratorOpToMemberFuncPtr<
             PrecisionT>;
 };
 template <class PrecisionT, class GateImplementation>
+struct ControlledGeneratorOpToMemberFuncPtr<
+    PrecisionT, GateImplementation, ControlledGeneratorOperation::PSWAP> {
+    constexpr static auto value =
+        &GateImplementation::template applyNCGeneratorPSWAP<PrecisionT>;
+};
+template <class PrecisionT, class GateImplementation>
 struct ControlledGeneratorOpToMemberFuncPtr<
     PrecisionT, GateImplementation, ControlledGeneratorOperation::MultiRZ> {
     constexpr static auto value =
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 47e65ed60b..52a88efb86 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
@@ -491,6 +491,14 @@ template auto GateImplementationsLM::applyGeneratorControlledPhaseShift(
 template auto GateImplementationsLM::applyGeneratorControlledPhaseShift(
     std::complex<float> *, std::size_t, const std::vector<std::size_t> &, bool)
     -> float;
+template auto
+GateImplementationsLM::applyGeneratorPSWAP(std::complex<double> *, std::size_t,
+                                           const std::vector<std::size_t> &,
+                                           bool) -> double;
+template auto
+GateImplementationsLM::applyGeneratorPSWAP(std::complex<float> *, std::size_t,
+                                           const std::vector<std::size_t> &,
+                                           bool) -> float;
 template auto GateImplementationsLM::applyGeneratorMultiRZ(
     std::complex<double> *, std::size_t, const std::vector<std::size_t> &, bool)
     -> double;
@@ -570,6 +578,13 @@ template auto GateImplementationsLM::applyNCGeneratorRZ<double>(
     std::complex<double> *, std::size_t, const std::vector<std::size_t> &,
     const std::vector<bool> &, const std::vector<std::size_t> &, bool)
     -> double;
+template auto GateImplementationsLM::applyNCGeneratorPSWAP<float>(
+    std::complex<float> *, std::size_t, const std::vector<std::size_t> &,
+    const std::vector<bool> &, const std::vector<std::size_t> &, bool) -> float;
+template auto GateImplementationsLM::applyNCGeneratorPSWAP<double>(
+    std::complex<double> *, std::size_t, const std::vector<std::size_t> &,
+    const std::vector<bool> &, const std::vector<std::size_t> &, bool)
+    -> double;
 template auto GateImplementationsLM::applyNCGeneratorSingleExcitation<float>(
     std::complex<float> *, std::size_t, const std::vector<std::size_t> &,
     const std::vector<bool> &, const std::vector<std::size_t> &, bool) -> float;
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 180e3387cc..3accca8313 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
@@ -2568,8 +2568,39 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
                                                     wires, adj);
     }
 
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyNCGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                          const std::vector<std::size_t> &controlled_wires,
+                          const std::vector<bool> &controlled_values,
+                          const std::vector<std::size_t> &wires,
+                          [[maybe_unused]] const bool adj) -> PrecisionT {
+        using ComplexT = std::complex<PrecisionT>;
+        constexpr ComplexT zero{0.0};
+        auto core_function =
+            [zero](ComplexT *arr, const std::size_t i00, const std::size_t i01,
+                   const std::size_t i10, const std::size_t i11) {
+                arr[i00] = zero;
+                arr[i11] = zero;
+                std::swap(arr[i10], arr[i01]);
+            };
+        applyNCGenerator2<PrecisionT, decltype(core_function)>(
+            arr, num_qubits, controlled_wires, controlled_values, wires,
+            core_function);
+        // NOLINTNEXTLINE(readability-magic-numbers)
+        return static_cast<PrecisionT>(1.0);
+    }
+
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                        const std::vector<std::size_t> &wires, bool adj)
+        -> PrecisionT {
+        return applyNCGeneratorPSWAP(arr, num_qubits, {}, {}, wires, adj);
+    }
+
     /**
-     * @brief Apply a single-qubit generator with controls to the
+     * @brief Apply a four-qubit generator with controls to the
      * statevector.
      *
      * @tparam PrecisionT Floating point precision of underlying statevector
diff --git a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_OpToMemberFuncPtr.cpp b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_OpToMemberFuncPtr.cpp
index 95f13c4e05..b4be24e4fa 100644
--- a/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_OpToMemberFuncPtr.cpp
+++ b/pennylane_lightning/core/src/simulators/lightning_qubit/gates/tests/Test_OpToMemberFuncPtr.cpp
@@ -189,6 +189,7 @@ class DummyImplementation {
     PENNYLANE_TESTS_DEFINE_GENERATOR_OP(DoubleExcitationPlus)
     PENNYLANE_TESTS_DEFINE_GENERATOR_OP(MultiRZ)
     PENNYLANE_TESTS_DEFINE_GENERATOR_OP(GlobalPhase)
+    PENNYLANE_TESTS_DEFINE_GENERATOR_OP(PSWAP)
 };
 
 static_assert(testAllGatesImplemented<float, float, DummyImplementation>(),
diff --git a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp
index a4c6e3673c..a61f35c8de 100644
--- a/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp
+++ b/pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp
@@ -1485,6 +1485,31 @@ static auto getPSWAP(const std::vector<U> &params) -> std::vector<CFP_t> {
     return getPSWAP<CFP_t>(params.front());
 }
 
+/**
+ * @brief Create a matrix representation of the PSWAP generator
+ * data in row-major format.
+ *
+ * @tparam CFP_t Required precision of gate (`float` or `double`).
+ * @tparam U Required precision of parameter (`float` or `double`).
+ * @return constexpr std::array<CFP_t>
+ */
+template <class CFP_t, class U = double>
+static constexpr auto getGeneratorPSWAP() -> std::vector<CFP_t> {
+    return {
+        cuUtil::ZERO<CFP_t>(), cuUtil::ZERO<CFP_t>(),
+        cuUtil::ZERO<CFP_t>(), cuUtil::ZERO<CFP_t>(),
+
+        cuUtil::ZERO<CFP_t>(), cuUtil::ZERO<CFP_t>(),
+        cuUtil::ONE<CFP_t>(),  cuUtil::ZERO<CFP_t>(),
+
+        cuUtil::ZERO<CFP_t>(), cuUtil::ONE<CFP_t>(),
+        cuUtil::ZERO<CFP_t>(), cuUtil::ZERO<CFP_t>(),
+
+        cuUtil::ZERO<CFP_t>(), cuUtil::ZERO<CFP_t>(),
+        cuUtil::ZERO<CFP_t>(), cuUtil::ZERO<CFP_t>(),
+    };
+}
+
 template <class CFP_t> static constexpr auto getP11_CU() -> std::vector<CFP_t> {
     return {cuUtil::ZERO<CFP_t>(), cuUtil::ZERO<CFP_t>(), cuUtil::ZERO<CFP_t>(),
             cuUtil::ONE<CFP_t>()};
diff --git a/pennylane_lightning/lightning_gpu/lightning_gpu.toml b/pennylane_lightning/lightning_gpu/lightning_gpu.toml
index d5058d99c7..87c4d4c641 100644
--- a/pennylane_lightning/lightning_gpu/lightning_gpu.toml
+++ b/pennylane_lightning/lightning_gpu/lightning_gpu.toml
@@ -58,7 +58,7 @@ DoubleExcitationMinus  = { properties = [ "invertible", "controllable", "differe
 MultiRZ                = { properties = [ "invertible", "controllable", "differentiable" ] }
 QubitUnitary           = { properties = [ "invertible", "controllable"                   ] }
 GlobalPhase            = { properties = [ "invertible", "controllable", "differentiable" ] }
-PSWAP                  = { properties = [ "invertible", "controllable",                  ] }
+PSWAP                  = { properties = [ "invertible", "controllable", "differentiable" ] }
 
 # Operations supported by the execution in Python but not directly supported by the backend
 [pennylane.operators.gates]
diff --git a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml
index a51021a03e..f450b99fcb 100644
--- a/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml
+++ b/pennylane_lightning/lightning_kokkos/lightning_kokkos.toml
@@ -45,7 +45,7 @@ PauliX                 = { properties = [ "invertible", "controllable", "differe
 PauliY                 = { properties = [ "invertible", "controllable", "differentiable" ] }
 PauliZ                 = { properties = [ "invertible", "controllable", "differentiable" ] }
 PhaseShift             = { properties = [ "invertible", "controllable", "differentiable" ] }
-PSWAP                  = { properties = [ "invertible", "controllable",                  ] }
+PSWAP                  = { properties = [ "invertible", "controllable", "differentiable" ] }
 QubitUnitary           = { properties = [ "invertible", "controllable"                   ] }
 Rot                    = { properties = [ "invertible", "controllable"                   ] }
 RX                     = { properties = [ "invertible", "controllable", "differentiable" ] }
diff --git a/pennylane_lightning/lightning_qubit/lightning_qubit.toml b/pennylane_lightning/lightning_qubit/lightning_qubit.toml
index 27845bccad..62cb44d57f 100644
--- a/pennylane_lightning/lightning_qubit/lightning_qubit.toml
+++ b/pennylane_lightning/lightning_qubit/lightning_qubit.toml
@@ -45,7 +45,7 @@ PauliX                 = { properties = [ "invertible", "controllable", "differe
 PauliY                 = { properties = [ "invertible", "controllable", "differentiable" ] }
 PauliZ                 = { properties = [ "invertible", "controllable", "differentiable" ] }
 PhaseShift             = { properties = [ "invertible", "controllable", "differentiable" ] }
-PSWAP                  = { properties = [ "invertible", "controllable",                  ] }
+PSWAP                  = { properties = [ "invertible", "controllable", "differentiable" ] }
 QubitUnitary           = { properties = [ "invertible", "controllable",                  ] }
 Rot                    = { properties = [ "invertible", "controllable",                  ] }
 RX                     = { properties = [ "invertible", "controllable", "differentiable" ] }
diff --git a/tests/test_adjoint_jacobian.py b/tests/test_adjoint_jacobian.py
index 51dcb3e29c..43f49919d1 100644
--- a/tests/test_adjoint_jacobian.py
+++ b/tests/test_adjoint_jacobian.py
@@ -617,6 +617,7 @@ def circuit(x, y, z):
             qml.CRY,
             qml.CRZ,
             qml.ControlledPhaseShift,
+            qml.PSWAP,
             qml.SingleExcitation,
             qml.SingleExcitationMinus,
             qml.SingleExcitationPlus,
@@ -681,6 +682,7 @@ def circuit(p):
             qml.CRY,
             qml.CRZ,
             qml.ControlledPhaseShift,
+            qml.PSWAP,
             qml.SingleExcitation,
             qml.SingleExcitationMinus,
             qml.SingleExcitationPlus,
@@ -742,6 +744,7 @@ def circuit(p):
             qml.IsingXY,
             qml.IsingYY,
             qml.IsingZZ,
+            qml.PSWAP,
             qml.SingleExcitation,
             qml.SingleExcitationMinus,
             qml.SingleExcitationPlus,


Reviews:
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:47:15Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:48:17Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:52:16Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:56:49Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:58:05Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:58:15Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:21:51Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:23:06Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:29:10Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:30:35Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:32:53Z
user: login: LuisAlfredoNu
body: Thank you @jzaia18 
Nice work!
A final question. Do we need python test for this implementation? 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:34:17Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:40:21Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:42:37Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:54:52Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:56:35Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:56:56Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T17:06:50Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T17:38:39Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T20:29:58Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T20:31:56Z
user: login: LuisAlfredoNu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T20:32:06Z
user: login: josephleekl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T20:56:30Z
user: login: josephleekl
body: Thanks @jzaia18 , awesome work! left some comments, happy to look again once addressed. also make sure that the c++ code you've written is actually used by Python (it should be, but it's good to be sure!) :) 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T21:12:21Z
user: login: jzaia18
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T21:20:46Z
user: login: maliasadi
body: Nice work! :star_struck: 

Don't forget to update the changelog and check the wheels :1st_place_medal: 
 
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T18:22:04Z
user: login: josephleekl
body: LGTM, thanks @jzaia18 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T13:58:45Z

Review comments:
diff_hunk: @@ -2568,8 +2568,39 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
                                                     wires, adj);
     }
 
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyNCGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                          const std::vector<std::size_t> &controlled_wires,
+                          const std::vector<bool> &controlled_values,
+                          const std::vector<std::size_t> &wires,
+                          [[maybe_unused]] const bool adj) -> PrecisionT {
+        constexpr std::complex<PrecisionT> zero{0.0};
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp
user: login: LuisAlfredoNu
body: 
```suggestion
        using ComplexT = std::complex<PrecisionT> 
        constexpr ComplexT zero{0.0};
```
Could you change the type in the rest of the function, please? 
created_at: 2025-03-19T14:47:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2568,8 +2568,39 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
                                                     wires, adj);
     }
 
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyNCGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                          const std::vector<std::size_t> &controlled_wires,
+                          const std::vector<bool> &controlled_values,
+                          const std::vector<std::size_t> &wires,
+                          [[maybe_unused]] const bool adj) -> PrecisionT {
+        constexpr std::complex<PrecisionT> zero{0.0};
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp
user: login: LuisAlfredoNu
body: hahaha It is only two definition :sweat_smile:
created_at: 2025-03-19T14:48:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1770,7 +1770,7 @@ TEMPLATE_TEST_CASE("Generators::applyControlledGenerator - 2 wires",
     const std::string controlled_gate_name =
         GENERATE("IsingXX", "IsingXY", "IsingYY", "IsingZZ", "SingleExcitation",
                  "SingleExcitationMinus", "SingleExcitationPlus", "GlobalPhase",
-                 "MultiRZ");
+                 "MultiRZ", "PSWAP");
path: pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp
user: login: LuisAlfredoNu
body: Where is the test for the non controlled generator? 
created_at: 2025-03-19T14:52:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1715,6 +1734,38 @@ class StateVectorCudaManaged
         return -static_cast<PrecisionT>(1.0);
     }
 
+    inline PrecisionT applyControlledGeneratorPSWAP(
+        const std::vector<std::size_t> &controlled_wires,
+        const std::vector<bool> &controlled_values,
+        const std::vector<std::size_t> &wires, bool adj = false) {
+        const std::size_t ctrl_size = controlled_wires.size();
+        const std::size_t tgt_size = wires.size();
+
+        // Generate permutation
+        std::vector<custatevecIndex_t> permutations =
+            generateTrivialPermutation(ctrl_size, tgt_size);
+        std::size_t index = controlPermutationMatrixIndex(ctrl_size, tgt_size,
+                                                          controlled_values);
+        std::swap(permutations[index + 1], permutations[index + 2]);
path: pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp
user: login: LuisAlfredoNu
body: why is `index+1` and `index+2`? 
created_at: 2025-03-19T14:56:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1715,6 +1734,38 @@ class StateVectorCudaManaged
         return -static_cast<PrecisionT>(1.0);
     }
 
+    inline PrecisionT applyControlledGeneratorPSWAP(
+        const std::vector<std::size_t> &controlled_wires,
+        const std::vector<bool> &controlled_values,
+        const std::vector<std::size_t> &wires, bool adj = false) {
+        const std::size_t ctrl_size = controlled_wires.size();
+        const std::size_t tgt_size = wires.size();
+
+        // Generate permutation
+        std::vector<custatevecIndex_t> permutations =
+            generateTrivialPermutation(ctrl_size, tgt_size);
+        std::size_t index = controlPermutationMatrixIndex(ctrl_size, tgt_size,
+                                                          controlled_values);
+        std::swap(permutations[index + 1], permutations[index + 2]);
path: pennylane_lightning/core/src/simulators/lightning_gpu/StateVectorCudaManaged.hpp
user: login: jzaia18
body: That's just what the PSWAP matrix looks like, the middle 2 rows are swapped
created_at: 2025-03-19T14:58:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1770,7 +1770,7 @@ TEMPLATE_TEST_CASE("Generators::applyControlledGenerator - 2 wires",
     const std::string controlled_gate_name =
         GENERATE("IsingXX", "IsingXY", "IsingYY", "IsingZZ", "SingleExcitation",
                  "SingleExcitationMinus", "SingleExcitationPlus", "GlobalPhase",
-                 "MultiRZ");
+                 "MultiRZ", "PSWAP");
path: pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp
user: login: jzaia18
body: Good catch
created_at: 2025-03-19T14:58:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -491,6 +491,14 @@ template auto GateImplementationsLM::applyGeneratorControlledPhaseShift(
 template auto GateImplementationsLM::applyGeneratorControlledPhaseShift(
     std::complex<float> *, std::size_t, const std::vector<std::size_t> &, bool)
     -> float;
+template auto
+GateImplementationsLM::applyGeneratorPSWAP(std::complex<double> *, std::size_t,
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.cpp
user: login: LuisAlfredoNu
body: Should we add `applyNCGenerator....`?
created_at: 2025-03-19T15:21:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2568,8 +2568,39 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
                                                     wires, adj);
     }
 
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyNCGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                          const std::vector<std::size_t> &controlled_wires,
+                          const std::vector<bool> &controlled_values,
+                          const std::vector<std::size_t> &wires,
+                          [[maybe_unused]] const bool adj) -> PrecisionT {
+        constexpr std::complex<PrecisionT> zero{0.0};
+        auto core_function =
+            [zero](std::complex<PrecisionT> *arr, const std::size_t i00,
+                   const std::size_t i01, const std::size_t i10,
+                   const std::size_t i11) {
+                arr[i00] = zero;
+                arr[i11] = zero;
+                std::swap(arr[i10], arr[i01]);
+            };
+        applyNCGenerator2<PrecisionT, decltype(core_function)>(
+            arr, num_qubits, controlled_wires, controlled_values, wires,
+            core_function);
+        // NOLINTNEXTLINE(readability-magic-numbers)
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp
user: login: LuisAlfredoNu
body: Why we have this line?
created_at: 2025-03-19T15:23:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -375,6 +378,9 @@ void assignKernelsForControlledGeneratorOp_Default() {
     instance.assignKernelForOp(ControlledGeneratorOperation::GlobalPhase,
                                all_threading, all_memory_model,
                                all_qubit_numbers, KernelType::LM);
+    instance.assignKernelForOp(ControlledGeneratorOperation::PSWAP,
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/AssignKernelMap_Default.cpp
user: login: LuisAlfredoNu
body: For future reference, Could you update the line position 325 to 288, please?
created_at: 2025-03-19T15:29:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -375,6 +378,9 @@ void assignKernelsForControlledGeneratorOp_Default() {
     instance.assignKernelForOp(ControlledGeneratorOperation::GlobalPhase,
                                all_threading, all_memory_model,
                                all_qubit_numbers, KernelType::LM);
+    instance.assignKernelForOp(ControlledGeneratorOperation::PSWAP,
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/AssignKernelMap_Default.cpp
user: login: LuisAlfredoNu
body: The same for L159 to L123
created_at: 2025-03-19T15:30:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1485,6 +1485,31 @@ static auto getPSWAP(const std::vector<U> &params) -> std::vector<CFP_t> {
     return getPSWAP<CFP_t>(params.front());
 }
 
+/**
+ * @brief Create a matrix representation of the PSWAP generator
+ * data in row-major format.
+ *
+ * @tparam CFP_t Required precision of gate (`float` or `double`).
+ * @tparam U Required precision of parameter (`float` or `double`).
+ * @return constexpr std::array<CFP_t>
+ */
+template <class CFP_t, class U = double>
+static constexpr auto getGeneratorPSWAP() -> std::vector<CFP_t> {
path: pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp
user: login: LuisAlfredoNu
body: Do we need this if used `cuPermutation`? 
created_at: 2025-03-19T15:32:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2568,8 +2568,39 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
                                                     wires, adj);
     }
 
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyNCGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                          const std::vector<std::size_t> &controlled_wires,
+                          const std::vector<bool> &controlled_values,
+                          const std::vector<std::size_t> &wires,
+                          [[maybe_unused]] const bool adj) -> PrecisionT {
+        constexpr std::complex<PrecisionT> zero{0.0};
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp
user: login: jzaia18
body: Fixed in 017d2258
created_at: 2025-03-19T15:40:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -491,6 +491,14 @@ template auto GateImplementationsLM::applyGeneratorControlledPhaseShift(
 template auto GateImplementationsLM::applyGeneratorControlledPhaseShift(
     std::complex<float> *, std::size_t, const std::vector<std::size_t> &, bool)
     -> float;
+template auto
+GateImplementationsLM::applyGeneratorPSWAP(std::complex<double> *, std::size_t,
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.cpp
user: login: jzaia18
body: Another good catch, although I'm not sure why this didn't give compiler errors... Maybe because applyGeneratorPSWAP calls this?
created_at: 2025-03-19T15:42:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2568,8 +2568,39 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
                                                     wires, adj);
     }
 
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyNCGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                          const std::vector<std::size_t> &controlled_wires,
+                          const std::vector<bool> &controlled_values,
+                          const std::vector<std::size_t> &wires,
+                          [[maybe_unused]] const bool adj) -> PrecisionT {
+        constexpr std::complex<PrecisionT> zero{0.0};
+        auto core_function =
+            [zero](std::complex<PrecisionT> *arr, const std::size_t i00,
+                   const std::size_t i01, const std::size_t i10,
+                   const std::size_t i11) {
+                arr[i00] = zero;
+                arr[i11] = zero;
+                std::swap(arr[i10], arr[i01]);
+            };
+        applyNCGenerator2<PrecisionT, decltype(core_function)>(
+            arr, num_qubits, controlled_wires, controlled_values, wires,
+            core_function);
+        // NOLINTNEXTLINE(readability-magic-numbers)
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp
user: login: jzaia18
body: The generators return a scalar which is the multiple that should be applied to the matrix (for PSWAP its just 1, but for some of the others its 1/2 for example). I did want to get clarification on why some of them are negative, since negatives should just be ignored as global phase I thought
created_at: 2025-03-19T15:54:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -491,6 +491,14 @@ template auto GateImplementationsLM::applyGeneratorControlledPhaseShift(
 template auto GateImplementationsLM::applyGeneratorControlledPhaseShift(
     std::complex<float> *, std::size_t, const std::vector<std::size_t> &, bool)
     -> float;
+template auto
+GateImplementationsLM::applyGeneratorPSWAP(std::complex<double> *, std::size_t,
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.cpp
user: login: jzaia18
body: Fixed in b6dfdd6e
created_at: 2025-03-19T15:56:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -375,6 +378,9 @@ void assignKernelsForControlledGeneratorOp_Default() {
     instance.assignKernelForOp(ControlledGeneratorOperation::GlobalPhase,
                                all_threading, all_memory_model,
                                all_qubit_numbers, KernelType::LM);
+    instance.assignKernelForOp(ControlledGeneratorOperation::PSWAP,
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/AssignKernelMap_Default.cpp
user: login: jzaia18
body: Fixed in b6dfdd6e
created_at: 2025-03-19T15:56:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1485,6 +1485,31 @@ static auto getPSWAP(const std::vector<U> &params) -> std::vector<CFP_t> {
     return getPSWAP<CFP_t>(params.front());
 }
 
+/**
+ * @brief Create a matrix representation of the PSWAP generator
+ * data in row-major format.
+ *
+ * @tparam CFP_t Required precision of gate (`float` or `double`).
+ * @tparam U Required precision of parameter (`float` or `double`).
+ * @return constexpr std::array<CFP_t>
+ */
+template <class CFP_t, class U = double>
+static constexpr auto getGeneratorPSWAP() -> std::vector<CFP_t> {
path: pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp
user: login: jzaia18
body: We talked about migrating gates in general to using permutation matrices, but that has its own story. For now, this one stays consistent with the impl of the other generators
created_at: 2025-03-19T17:06:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1770,7 +1770,7 @@ TEMPLATE_TEST_CASE("Generators::applyControlledGenerator - 2 wires",
     const std::string controlled_gate_name =
         GENERATE("IsingXX", "IsingXY", "IsingYY", "IsingZZ", "SingleExcitation",
                  "SingleExcitationMinus", "SingleExcitationPlus", "GlobalPhase",
-                 "MultiRZ");
+                 "MultiRZ", "PSWAP");
path: pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp
user: login: jzaia18
body: Fixed in 26beda3f
created_at: 2025-03-19T17:38:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2568,8 +2568,39 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
                                                     wires, adj);
     }
 
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyNCGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                          const std::vector<std::size_t> &controlled_wires,
+                          const std::vector<bool> &controlled_values,
+                          const std::vector<std::size_t> &wires,
+                          [[maybe_unused]] const bool adj) -> PrecisionT {
+        constexpr std::complex<PrecisionT> zero{0.0};
+        auto core_function =
+            [zero](std::complex<PrecisionT> *arr, const std::size_t i00,
+                   const std::size_t i01, const std::size_t i10,
+                   const std::size_t i11) {
+                arr[i00] = zero;
+                arr[i11] = zero;
+                std::swap(arr[i10], arr[i01]);
+            };
+        applyNCGenerator2<PrecisionT, decltype(core_function)>(
+            arr, num_qubits, controlled_wires, controlled_values, wires,
+            core_function);
+        // NOLINTNEXTLINE(readability-magic-numbers)
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp
user: login: LuisAlfredoNu
body: No, I refer to `// NOLINTNEXTLINE(readability-magic-numbers)`
created_at: 2025-03-19T20:29:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2568,8 +2568,39 @@ class GateImplementationsLM : public PauliGenerator<GateImplementationsLM> {
                                                     wires, adj);
     }
 
+    template <class PrecisionT>
+    [[nodiscard]] static auto
+    applyNCGeneratorPSWAP(std::complex<PrecisionT> *arr, std::size_t num_qubits,
+                          const std::vector<std::size_t> &controlled_wires,
+                          const std::vector<bool> &controlled_values,
+                          const std::vector<std::size_t> &wires,
+                          [[maybe_unused]] const bool adj) -> PrecisionT {
+        constexpr std::complex<PrecisionT> zero{0.0};
+        auto core_function =
+            [zero](std::complex<PrecisionT> *arr, const std::size_t i00,
+                   const std::size_t i01, const std::size_t i10,
+                   const std::size_t i11) {
+                arr[i00] = zero;
+                arr[i11] = zero;
+                std::swap(arr[i10], arr[i01]);
+            };
+        applyNCGenerator2<PrecisionT, decltype(core_function)>(
+            arr, num_qubits, controlled_wires, controlled_values, wires,
+            core_function);
+        // NOLINTNEXTLINE(readability-magic-numbers)
path: pennylane_lightning/core/src/simulators/lightning_qubit/gates/cpu_kernels/GateImplementationsLM.hpp
user: login: jzaia18
body: Oh gotcha, that's to prevent warnings from the linter about the fact that we have a hard-coded value there. The other generators have a similar comment
created_at: 2025-03-19T20:31:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1485,6 +1485,31 @@ static auto getPSWAP(const std::vector<U> &params) -> std::vector<CFP_t> {
     return getPSWAP<CFP_t>(params.front());
 }
 
+/**
+ * @brief Create a matrix representation of the PSWAP generator
+ * data in row-major format.
+ *
+ * @tparam CFP_t Required precision of gate (`float` or `double`).
+ * @tparam U Required precision of parameter (`float` or `double`).
+ * @return constexpr std::array<CFP_t>
+ */
+template <class CFP_t, class U = double>
+static constexpr auto getGeneratorPSWAP() -> std::vector<CFP_t> {
path: pennylane_lightning/core/src/utils/cuda_utils/cuGates_host.hpp
user: login: LuisAlfredoNu
body: Oooh I was confused. Thks
created_at: 2025-03-19T20:32:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -160,6 +160,43 @@ TEST_CASE("Generators::applyGeneratorPhaseShift", "[GateGenerators]") {
     }
 }
 
+TEST_CASE("Generators::applyGeneratorPSWAP", "[GateGenerators]") {
+    // grad(PhaseShift) = grad(e^{i*0.5*a}*e^{-i*0.5*PauliZ*a}) => -i|1><1|
path: pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp
user: login: josephleekl
body: can you update this line? 
created_at: 2025-03-19T20:56:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -160,6 +160,43 @@ TEST_CASE("Generators::applyGeneratorPhaseShift", "[GateGenerators]") {
     }
 }
 
+TEST_CASE("Generators::applyGeneratorPSWAP", "[GateGenerators]") {
+    // grad(PhaseShift) = grad(e^{i*0.5*a}*e^{-i*0.5*PauliZ*a}) => -i|1><1|
path: pennylane_lightning/core/src/simulators/lightning_gpu/gates/tests/Test_StateVectorCudaManaged_Generators.cpp
user: login: jzaia18
body: Whoops, meant to remove that comment
created_at: 2025-03-19T21:20:46Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-14T20:57:11Z
body: Hello. You may have forgotten to update the changelog!
Please edit [.github/CHANGELOG.md](/PennyLaneAI/pennylane-lightning/blob/master/.github/CHANGELOG.md) with:
* A one-to-two sentence description of the change. You may include a small working example for new features.
* A link back to this PR.
* Your name (or GitHub username) in the contributors section.
author_association: CONTRIBUTOR
user: login: codecov[bot]
created_at: 2025-03-14T21:00:35Z
body: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane-lightning/pull/1093?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
Attention: Patch coverage is `98.75000%` with `1 line` in your changes missing coverage. Please review.
> Please [upload](https://docs.codecov.com/docs/codecov-uploader) report for BASE (`feature/pswap-impl-base@4cc5fd3`). [Learn more](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#section-missing-base-commit) about missing BASE report.

| [Files with missing lines](https://app.codecov.io/gh/PennyLaneAI/pennylane-lightning/pull/1093?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Patch % | Lines |
|---|---|---|
| [...tning\_qubit/gates/tests/Test\_OpToMemberFuncPtr.cpp](https://app.codecov.io/gh/PennyLaneAI/pennylane-lightning/pull/1093?src=pr&el=tree&filepath=pennylane_lightning%2Fcore%2Fsrc%2Fsimulators%2Flightning_qubit%2Fgates%2Ftests%2FTest_OpToMemberFuncPtr.cpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lX2xpZ2h0bmluZy9jb3JlL3NyYy9zaW11bGF0b3JzL2xpZ2h0bmluZ19xdWJpdC9nYXRlcy90ZXN0cy9UZXN0X09wVG9NZW1iZXJGdW5jUHRyLmNwcA==) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/PennyLaneAI/pennylane-lightning/pull/1093?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) |

<details><summary>Additional details and impacted files</summary>


```diff
@@                    Coverage Diff                     @@
##             feature/pswap-impl-base    #1093   +/-   ##
==========================================================
  Coverage                           ?   98.83%           
==========================================================
  Files                              ?      235           
  Lines                              ?    40064           
  Branches                           ?        0           
==========================================================
  Hits                               ?    39598           
  Misses                             ?      466           
  Partials                           ?        0           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane-lightning/pull/1093?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: jzaia18
created_at: 2025-03-19T16:06:46Z
body: As far as I can tell, none of the other gates' generators have extra tests in the Python end. It's possible this is already handled by the gate tests? (Although it doesn't seem to be explicitly....)
author_association: CONTRIBUTOR
user: login: josephleekl
created_at: 2025-03-19T21:09:45Z
body: > As far as I can tell, none of the other gates' generators have extra tests in the Python end. It's possible this is already handled by the gate tests? (Although it doesn't seem to be explicitly....)

so the generators are used by jacobians, so have a look at e.g. these tests:
https://github.com/PennyLaneAI/pennylane-lightning/blob/2774e8915ed7812c63d06db6f3a3d0c5a6da3a31/tests/test_adjoint_jacobian.py#L632
https://github.com/PennyLaneAI/pennylane-lightning/blob/2774e8915ed7812c63d06db6f3a3d0c5a6da3a31/tests/test_adjoint_jacobian.py#L696
https://github.com/PennyLaneAI/pennylane-lightning/blob/2774e8915ed7812c63d06db6f3a3d0c5a6da3a31/tests/test_adjoint_jacobian.py#L758

and see if they hit your code :)
author_association: CONTRIBUTOR