Skip to content

Commit

Permalink
Finalize the LM kernel (#212)
Browse files Browse the repository at this point in the history
* Complete all tests
* Complete all gate implementations
* Add compile-time tests
* Refactor `DynamicDispatcher` and gate implementations.

Co-authored-by: Lee James O'Riordan <mlxd@users.noreply.github.com>
Co-authored-by: Ali Asadi <ali@xanadu.ai>
  • Loading branch information
3 people authored Feb 12, 2022
1 parent 5b14d13 commit 2cb2727
Show file tree
Hide file tree
Showing 76 changed files with 8,646 additions and 3,911 deletions.
10 changes: 6 additions & 4 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@

### Improvements

* Update adjointJacobian and VJP methods.
[(#222)](https://github.com/PennyLaneAI/pennylane-lightning/pull/222)

* Set GitHub workflow to upload wheels to Test PyPI [(#220)](https://github.com/PennyLaneAI/pennylane-lightning/pull/220).

* Finalize the new kernel implementation [(#212)](https://github.com/PennyLaneAI/pennylane-lightning/pull/212).

### Documentation

### Bug fixes
Expand All @@ -18,7 +23,7 @@

This release contains contributions from (in alphabetical order):

Chae-Yeun Park
Ali Asadi, Chae-Yeun Park

---

Expand All @@ -44,9 +49,6 @@ Chae-Yeun Park
* Ensure debug info is built into dynamic libraries.
[(#201)](https://github.com/PennyLaneAI/pennylane-lightning/pull/201)

* Update adjointJacobian and VJP methods.
[(#222)](https://github.com/PennyLaneAI/pennylane-lightning/pull/222)

### Documentation

### Bug fixes
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ venv/
doc/_build/
PennyLane_Lightning.egg-info/
build/
Build/
BuildBench/
BuildTests/
dist/
Expand Down
10 changes: 6 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,13 @@ target_include_directories(pennylane_lightning INTERFACE "pennylane_lightning/sr
#####################################################

pybind11_add_module(lightning_qubit_ops "pennylane_lightning/src/bindings/Bindings.cpp")
target_link_libraries(lightning_qubit_ops PRIVATE lightning_compile_options
lightning_external_libs
lightning_utils
target_link_libraries(lightning_qubit_ops PRIVATE lightning_algorithms
lightning_gates
lightning_simulator
lightning_algorithms)
lightning_utils)

target_link_libraries(lightning_qubit_ops PRIVATE lightning_compile_options
lightning_external_libs)
set_target_properties(lightning_qubit_ops PROPERTIES CXX_VISIBILITY_PRESET hidden)

target_compile_definitions(lightning_qubit_ops PRIVATE VERSION_INFO=${VERSION_STRING})
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ docs:
clean-docs:
$(MAKE) -C doc clean

.PHONY : test-builtin test-suite test-python coverage test-cpp
test-builtin:
$(PYTHON) -I $(TESTRUNNER)

Expand Down Expand Up @@ -117,5 +118,5 @@ endif
.PHONY: check-tidy
check-tidy:
rm -rf ./Build
cmake . -BBuild -DENABLE_CLANG_TIDY=ON -DBUILD_TESTS=1
cmake . -BBuild -DENABLE_CLANG_TIDY=ON -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON
cmake --build ./Build
84 changes: 37 additions & 47 deletions doc/add_kernel.rst
Original file line number Diff line number Diff line change
@@ -1,74 +1,52 @@
.. _lightning_add_gate_implementation:

Adding a gate implementation
############################

We discuss how one can add another gate implementation in this document. Assume that you want to add a custom ``PauliX`` gate implementation in Pennylane-Lightning. In this case, you may first add a template class as:
We discuss how one can add another gate implementation in this document. Assume that you want to add a custom ``PauliX`` gate implementation in Pennylane-Lightning. In this case, you may first create a file and add a class:

.. code-block:: cpp
template <class PrecisionT>
// file: MyGateImplementation.hpp
struct MyGateImplementation {
constexpr static implemented_gates = {GateOperations::PauliX};
public:
constexpr static std::array implemented_gates = {
GateOperation::PauliX
}; // List of implemented gates
constexpr static kernel_id = KernelType::Mykernel; // Will be discussed below
constexpr static std::string_view = "MyGateImpl"; // Name of your kernel
template <class PrecisionT>
static void applyPauliX(std::complex<PrecisionT>* data,
size_t num_qubits,
const std::vector<size_t>& wires,
[[maybe_unused]] bool inverse) {
/* Write your implementation */
...
}
static void applyPauliY(std::complex<PrecisionT>* data,
size_t num_qubits,
const std::vector<size_t>& wires,
[[maybe_unused]] bool inverse) {
PL_ABORT("MyGateImplementation::applyPauliY is not implemented");
}
/* All other gates */
...
};
Note that all member functions must be defined to prevent compile errors (this requirement may be deprecated in the near future).

Then you can add your gate implementation to Pennylane-Lightning by doing followings:
Then you can add your gate implementation to Pennylane-Lightning. This can be done my modifying two files as:

.. code-block:: cpp
// file: simulator/KernelType.hpp
namespace Pennylane {
enum class KernelType { PI, LM, MyKernel /* This is added */, Unknown };
namespace Constant {
constexpr std::array available_kernels = {
std::pair<KernelType, std::string_view>{KernelType::PI, "PI"},
std::pair<KernelType, std::string_view>{KernelType::LM, "LM"},
/* The following line is added */
std::pair<KernelType, std::string_view>{KernelType::MyKernel, "MyKernel"},
};
enum class KernelType { PI, LM, MyKernel /* This is added */, None };
/* Rest of the file */
} // namespace Pennylane
and

.. code-block:: cpp
// file: simulator/SelectGateOps.hpp
// file: simulator/AvailableKernels.hpp
namespace Pennylane {
...
/* Some code */
template <class fp_t, KernelType kernel> class SelectGateOps {};
template <class fp_t>
class SelectGateOps<fp_t, KernelType::PI> : public GateOperationsPI<fp_t> {};
template <class fp_t>
class SelectGateOps<fp_t, KernelType::LM> : public GateOperationsLM<fp_t> {};
/* Add the following lines */
template <class fp_t>
class SelectGateOps<fp_t, KernelType::MyKernel> : public MyGateImplementation<fp_t> {};
using AvailableKernels = Util::TypeList<GateImplementationsLM,
GateImplementationsPI,
MyGateImplementation /* This is added*/>;
} // namespace Pennylane
Expand Down Expand Up @@ -106,10 +84,8 @@ To make your gate implementation default, you need to change ``default_kernel_fo

.. code-block:: cpp
// file: simulator/SelectGateOps.hpp
constexpr std::array<std::pair<GateOperations, KernelType>,
static_cast<int>(GateOperations::END)>
default_kernel_for_ops = {
// file: simulator/Constant.hpp
constexpr std::array default_kernel_for_gates = {
std::pair{GateOperations::PauliX, KernelType::LM},
std::pair{GateOperations::PauliY, KernelType::LM},
...
Expand All @@ -119,12 +95,26 @@ to

.. code-block:: cpp
constexpr std::array<std::pair<GateOperations, KernelType>,
static_cast<int>(GateOperations::END)>
default_kernel_for_ops = {
constexpr std::array default_kernel_for_gates = {
std::pair{GateOperations::PauliX, KernelType::MyKernel},
std::pair{GateOperations::PauliY, KernelType::LM},
...
}
will make your implementation as default kernel for ``PauliX`` gate (for all C++ call as well as for the Python binding).
will make your implementation as default kernel for ``PauliX`` gate (for all C++ calls as well as for the Python binding).

Gate generators can also be handled in the same way.

Test your gate implementation
=============================

To test your own kernel implementations, you can go to ``tests/TestKernels.hpp`` and add your implementation.

.. code-block:: cpp
using TestKernels = Pennylane::Util::TypeList<Pennylane::Gates::GateImplementationsLM,
Pennylane::Gates::GateImplementationsPI,
MyGateImplementation /*This is added */>;
It will automatically test your gate implementation.
Note that, in the current implementation, this will test a gate if ``apply + gate name`` is defined even when the gate is not included in ``implemented_gates`` variable.
2 changes: 1 addition & 1 deletion pennylane_lightning/_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.22.0-dev4"
__version__ = "0.22.0-dev5"
4 changes: 0 additions & 4 deletions pennylane_lightning/lightning_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@


UNSUPPORTED_PARAM_GATES_ADJOINT = (
"MultiRZ",
"IsingXX",
"IsingYY",
"IsingZZ",
"SingleExcitation",
"SingleExcitationPlus",
"SingleExcitationMinus",
Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/src/.clang-tidy
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,-llvmlibc-*,modernize-*,-modernize-use-trailing-return-type,clang-analyzer-cplusplus*,openmp-*,performance-*,portability-*,readability-*,hicpp-signed-bitwise'
Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,-llvmlibc-*,modernize-*,-modernize-use-trailing-return-type,clang-analyzer-cplusplus*,openmp-*,performance-*,portability-*,readability-*,hicpp-*,-hicpp-no-array-decay,bugprone-suspicious-*,llvm-namespace-comment,'
WarningsAsErrors: '*'
HeaderFilterRegex: '.*'
AnalyzeTemporaryDtors: false
Expand Down
6 changes: 4 additions & 2 deletions pennylane_lightning/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ project(lightning_components LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)

option(ENABLE_WARNINGS "Enable warnings" ON)
option(ENABLE_OPENMP "Enable OpenMP" ON)

if(ENABLE_CLANG_TIDY)
if(NOT DEFINED CLANG_TIDY_BINARY)
Expand All @@ -25,8 +26,9 @@ include("${PROJECT_SOURCE_DIR}/../../cmake/process_options.cmake")
###############################################################################
# Include all nested sources directories
###############################################################################
set(COMPONENT_SUBDIRS simulator;
algorithms;
set(COMPONENT_SUBDIRS algorithms;
gates;
simulator;
util;
)
foreach(COMP ${COMPONENT_SUBDIRS})
Expand Down
92 changes: 4 additions & 88 deletions pennylane_lightning/src/algorithms/AdjointDiff.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
#include <numeric>
#include <stdexcept>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>

#include "DynamicDispatcher.hpp"
#include "Error.hpp"
#include "JacobianTape.hpp"
#include "LinearAlgebra.hpp"
Expand All @@ -36,70 +36,10 @@ namespace {
using namespace Pennylane;
using namespace Pennylane::Util;

template <class T>
static constexpr auto getP00() -> std::vector<std::complex<T>> {
return {ONE<T>(), ZERO<T>(), ZERO<T>(), ZERO<T>()};
}

template <class T>
static constexpr auto getP11() -> std::vector<std::complex<T>> {
return {ZERO<T>(), ZERO<T>(), ZERO<T>(), ONE<T>()};
}

template <class T = double, class SVType>
void applyGeneratorRX(SVType &sv, const std::vector<size_t> &wires,
const bool adj = false) {
sv.applyPauliX(wires, adj);
}

template <class T = double, class SVType>
void applyGeneratorRY(SVType &sv, const std::vector<size_t> &wires,
const bool adj = false) {
sv.applyPauliY(wires, adj);
}

template <class T = double, class SVType>
void applyGeneratorRZ(SVType &sv, const std::vector<size_t> &wires,
const bool adj = false) {
sv.applyPauliZ(wires, adj);
}

template <class T, class SVType>
void applyGeneratorPhaseShift(SVType &sv, const std::vector<size_t> &wires,
const bool adj = false) {
sv.applyGeneratorPhaseShift(wires, adj);
}

template <class T, class SVType>
void applyGeneratorCRX(SVType &sv, const std::vector<size_t> &wires,
[[maybe_unused]] const bool adj = false) {
sv.applyGeneratorCRX(wires, adj);
}

template <class T, class SVType>
void applyGeneratorCRY(SVType &sv, const std::vector<size_t> &wires,
[[maybe_unused]] const bool adj = false) {
sv.applyGeneratorCRY(wires, adj);
}

template <class T, class SVType>
void applyGeneratorCRZ(SVType &sv, const std::vector<size_t> &wires,
[[maybe_unused]] const bool adj = false) {
sv.applyGeneratorCRZ(wires, adj);
}

template <class T, class SVType>
void applyGeneratorControlledPhaseShift(SVType &sv,
const std::vector<size_t> &wires,
const bool adj = false) {
sv.applyGeneratorControlledPhaseShift(wires, adj);
}

} // namespace
/// @endcond

namespace Pennylane::Algorithms {

/**
* @brief Represent the logic for the adjoint Jacobian method of
* arXiV:2009.02823
Expand All @@ -112,29 +52,6 @@ template <class T = double> class AdjointJacobian {
const std::vector<size_t> &,
const bool); // function pointer type

// Holds the mapping from gate labels to associated generator functions.
const std::unordered_map<std::string, GeneratorFunc> generator_map{
{"RX", &::applyGeneratorRX<T, StateVectorManaged<T>>},
{"RY", &::applyGeneratorRY<T, StateVectorManaged<T>>},
{"RZ", &::applyGeneratorRZ<T, StateVectorManaged<T>>},
{"PhaseShift", &::applyGeneratorPhaseShift<T, StateVectorManaged<T>>},
{"CRX", &::applyGeneratorCRX<T, StateVectorManaged<T>>},
{"CRY", &::applyGeneratorCRY<T, StateVectorManaged<T>>},
{"CRZ", &::applyGeneratorCRZ<T, StateVectorManaged<T>>},
{"ControlledPhaseShift",
&::applyGeneratorControlledPhaseShift<T, StateVectorManaged<T>>}};

// Holds the mappings from gate labels to associated generator coefficients.
const std::unordered_map<std::string, T> scaling_factors{
{"RX", -static_cast<T>(0.5)},
{"RY", -static_cast<T>(0.5)},
{"RZ", -static_cast<T>(0.5)},
{"PhaseShift", static_cast<T>(1)},
{"CRX", -static_cast<T>(0.5)},
{"CRY", -static_cast<T>(0.5)},
{"CRZ", -static_cast<T>(0.5)},
{"ControlledPhaseShift", static_cast<T>(1)}};

/**
* @brief Utility method to update the Jacobian at a given index by
* calculating the overlap between two given states.
Expand Down Expand Up @@ -365,12 +282,12 @@ template <class T = double> class AdjointJacobian {
* @param adj Indicate whether to take the adjoint of the operation.
* @return T Generator scaling coefficient.
*/
inline auto applyGenerator(StateVectorManaged<T> &sv,
template <class SVType>
inline auto applyGenerator(StateVectorBase<T, SVType> &sv,
const std::string &op_name,
const std::vector<size_t> &wires, const bool adj)
-> T {
generator_map.at(op_name)(sv, wires, adj);
return scaling_factors.at(op_name);
return sv.applyGenerator(op_name, wires, adj);
}

public:
Expand Down Expand Up @@ -485,5 +402,4 @@ template <class T = double> class AdjointJacobian {
jac = Transpose(jac, jd.getNumParams(), num_observables);
}
}; // class AdjointJacobian

} // namespace Pennylane::Algorithms
Loading

0 comments on commit 2cb2727

Please sign in to comment.