Skip to content

Commit

Permalink
Add GateImplementationsLM::applyGeneratorDoubleExcitation(Minus/Plus)… (
Browse files Browse the repository at this point in the history
#512)

* Add failing tests.

* Add revWireParityN.

* Fix applyMultiQubitOp implementation.

* Auto update version

* Update changelog

* Refactor revWireParity overloads.

* WIP fix Kokkos too.

* Fix bug in multiQubitOpFunctor

* Refactor unitary/hermitian tests and fix L-Kokkos multiQubit kernels.

* Fix L-Qubit BitUtil.

* Include algorithm header in BitUtil (sort).

* Fix tidy issue. Fix failing test.

* Make wires2Parity inline.

* Update changelog.

* Update pennylane_lightning/core/src/utils/BitUtil.hpp

Co-authored-by: Amintor Dusko <[email protected]>

* Add GateImplementationsLM::applyGeneratorDoubleExcitation(Minus/Plus) kernels.

* Update changelog.

* Reduce 4-qubit gate LM kernels.

* Add parity2indices functions to reduce boilerplate.

* Auto update version

* trigger CI

---------

Co-authored-by: Dev version update bot <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Amintor Dusko <[email protected]>
  • Loading branch information
3 people authored Oct 11, 2023
1 parent 5cb3a67 commit c37d79c
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 151 deletions.
3 changes: 3 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

### Breaking changes

* Implement `LM::GeneratorDoubleExcitation`, `LM::GeneratorDoubleExcitationMinus`, `LM::GeneratorDoubleExcitationPlus` kernels. L-Qubit default kernels are now strictly from the `LM` implementation, which requires less memory and is faster for large state vectors.
[(#512)](https://github.com/PennyLaneAI/pennylane-lightning/pull/512)

* Add workflows validating compatibility between PennyLane and Lightning's most recent stable releases and development (latest) versions.
[(#507)](https://github.com/PennyLaneAI/pennylane-lightning/pull/507)
[(#498)](https://github.com/PennyLaneAI/pennylane-lightning/pull/498)
Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/core/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.33.0-dev17"
__version__ = "0.33.0-dev18"
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,13 @@ void assignKernelsForGeneratorOp_Default() {
all_qubit_numbers, KernelType::LM);
instance.assignKernelForOp(GeneratorOperation::DoubleExcitation,
all_threading, all_memory_model,
all_qubit_numbers, KernelType::PI);
all_qubit_numbers, KernelType::LM);
instance.assignKernelForOp(GeneratorOperation::DoubleExcitationPlus,
all_threading, all_memory_model,
all_qubit_numbers, KernelType::PI);
all_qubit_numbers, KernelType::LM);
instance.assignKernelForOp(GeneratorOperation::DoubleExcitationMinus,
all_threading, all_memory_model,
all_qubit_numbers, KernelType::PI);
all_qubit_numbers, KernelType::LM);

instance.assignKernelForOp(GeneratorOperation::MultiRZ, all_threading,
all_memory_model, all_qubit_numbers,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,116 @@ auto GateImplementationsLM::applyGeneratorSingleExcitationPlus(
return -static_cast<PrecisionT>(0.5);
}

template <class PrecisionT>
auto GateImplementationsLM::applyGeneratorDoubleExcitation(
std::complex<PrecisionT> *arr, std::size_t num_qubits,
const std::vector<std::size_t> &wires, [[maybe_unused]] bool adj)
-> PrecisionT {
using ComplexT = std::complex<PrecisionT>;
PL_ASSERT(wires.size() == 4);
constexpr ComplexT zero{};
constexpr ComplexT imag{0, 1};
constexpr std::size_t one{1};

const std::array<std::size_t, 4> rev_wires{
num_qubits - wires[3] - 1, num_qubits - wires[2] - 1,
num_qubits - wires[1] - 1, num_qubits - wires[0] - 1};

const std::array<std::size_t, 4> rev_wire_shifts{
one << rev_wires[0], one << rev_wires[1], one << rev_wires[2],
one << rev_wires[3]};

const auto parity = Pennylane::Util::revWireParity(rev_wires);

for (std::size_t k = 0; k < exp2(num_qubits - 4); k++) {
const auto indices =
GateImplementationsLM::parity2indices(k, parity, rev_wire_shifts);
const ComplexT v3 = arr[indices[0B0011]];
const ComplexT v12 = arr[indices[0B1100]];
for (const auto &i : indices) {
arr[i] = zero;
}
arr[indices[0B0011]] = -v12 * imag;
arr[indices[0B1100]] = v3 * imag;
}
// NOLINTNEXTLINE(readability - magic - numbers)
return -static_cast<PrecisionT>(0.5);
}

template <class PrecisionT>
auto GateImplementationsLM::applyGeneratorDoubleExcitationMinus(
std::complex<PrecisionT> *arr, std::size_t num_qubits,
const std::vector<std::size_t> &wires, [[maybe_unused]] bool adj)
-> PrecisionT {
using ComplexT = std::complex<PrecisionT>;
PL_ASSERT(wires.size() == 4);
constexpr ComplexT imag{0, 1};
constexpr std::size_t one{1};

const std::array<std::size_t, 4> rev_wires{
num_qubits - wires[3] - 1, num_qubits - wires[2] - 1,
num_qubits - wires[1] - 1, num_qubits - wires[0] - 1};

const std::array<std::size_t, 4> rev_wire_shifts{
one << rev_wires[0], one << rev_wires[1], one << rev_wires[2],
one << rev_wires[3]};

const auto parity = Pennylane::Util::revWireParity(rev_wires);

for (std::size_t k = 0; k < exp2(num_qubits - 4); k++) {
const std::size_t i0000 =
((k << 4U) & parity[4]) | ((k << 3U) & parity[3]) |
((k << 2U) & parity[2]) | ((k << 1U) & parity[1]) | (k & parity[0]);
const std::size_t i0011 =
i0000 | rev_wire_shifts[1] | rev_wire_shifts[0];
const std::size_t i1100 =
i0000 | rev_wire_shifts[3] | rev_wire_shifts[2];

arr[i0011] *= imag;
arr[i1100] *= -imag;
swap(arr[i1100], arr[i0011]);
}
// NOLINTNEXTLINE(readability - magic - numbers)
return -static_cast<PrecisionT>(0.5);
}

template <class PrecisionT>
auto GateImplementationsLM::applyGeneratorDoubleExcitationPlus(
std::complex<PrecisionT> *arr, std::size_t num_qubits,
const std::vector<std::size_t> &wires, [[maybe_unused]] bool adj)
-> PrecisionT {
using ComplexT = std::complex<PrecisionT>;
PL_ASSERT(wires.size() == 4);
constexpr ComplexT imag{0, 1};
constexpr std::size_t one{1};

const std::array<std::size_t, 4> rev_wires{
num_qubits - wires[3] - 1, num_qubits - wires[2] - 1,
num_qubits - wires[1] - 1, num_qubits - wires[0] - 1};

const std::array<std::size_t, 4> rev_wire_shifts{
one << rev_wires[0], one << rev_wires[1], one << rev_wires[2],
one << rev_wires[3]};

const auto parity = Pennylane::Util::revWireParity(rev_wires);

for (std::size_t k = 0; k < exp2(num_qubits - 4); k++) {
const std::size_t i0000 =
((k << 4U) & parity[4]) | ((k << 3U) & parity[3]) |
((k << 2U) & parity[2]) | ((k << 1U) & parity[1]) | (k & parity[0]);
const std::size_t i0011 =
i0000 | rev_wire_shifts[1] | rev_wire_shifts[0];
const std::size_t i1100 =
i0000 | rev_wire_shifts[3] | rev_wire_shifts[2];

arr[i0011] *= -imag;
arr[i1100] *= imag;
swap(arr[i1100], arr[i0011]);
}
// NOLINTNEXTLINE(readability - magic - numbers)
return static_cast<PrecisionT>(0.5);
}

// Explicit instantiation starts
/* Matrix operations */
template void GateImplementationsLM::applySingleQubitOp<float>(
Expand Down Expand Up @@ -571,6 +681,31 @@ template auto GateImplementationsLM::applyGeneratorSingleExcitationPlus<double>(
std::complex<double> *arr, size_t num_qubits,
const std::vector<size_t> &wires, [[maybe_unused]] bool adj) -> double;

template auto GateImplementationsLM::applyGeneratorDoubleExcitation<float>(
std::complex<float> *arr, size_t num_qubits,
const std::vector<size_t> &wires, [[maybe_unused]] bool adj) -> float;

template auto GateImplementationsLM::applyGeneratorDoubleExcitation<double>(
std::complex<double> *arr, size_t num_qubits,
const std::vector<size_t> &wires, [[maybe_unused]] bool adj) -> double;

template auto GateImplementationsLM::applyGeneratorDoubleExcitationMinus<float>(
std::complex<float> *arr, size_t num_qubits,
const std::vector<size_t> &wires, [[maybe_unused]] bool adj) -> float;

template auto
GateImplementationsLM::applyGeneratorDoubleExcitationMinus<double>(
std::complex<double> *arr, size_t num_qubits,
const std::vector<size_t> &wires, [[maybe_unused]] bool adj) -> double;

template auto GateImplementationsLM::applyGeneratorDoubleExcitationPlus<float>(
std::complex<float> *arr, size_t num_qubits,
const std::vector<size_t> &wires, [[maybe_unused]] bool adj) -> float;

template auto GateImplementationsLM::applyGeneratorDoubleExcitationPlus<double>(
std::complex<double> *arr, size_t num_qubits,
const std::vector<size_t> &wires, [[maybe_unused]] bool adj) -> double;

// Explicit instantiations ends

} // namespace Pennylane::LightningQubit::Gates
Loading

0 comments on commit c37d79c

Please sign in to comment.