Skip to content

Commit 2cb2727

Browse files
chaeyeunparkmlxdmaliasadi
authored
Finalize the LM kernel (#212)
* Complete all tests * Complete all gate implementations * Add compile-time tests * Refactor `DynamicDispatcher` and gate implementations. Co-authored-by: Lee James O'Riordan <[email protected]> Co-authored-by: Ali Asadi <[email protected]>
1 parent 5b14d13 commit 2cb2727

File tree

76 files changed

+8646
-3911
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+8646
-3911
lines changed

.github/CHANGELOG.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66

77
### Improvements
88

9+
* Update adjointJacobian and VJP methods.
10+
[(#222)](https://github.com/PennyLaneAI/pennylane-lightning/pull/222)
11+
912
* Set GitHub workflow to upload wheels to Test PyPI [(#220)](https://github.com/PennyLaneAI/pennylane-lightning/pull/220).
1013

14+
* Finalize the new kernel implementation [(#212)](https://github.com/PennyLaneAI/pennylane-lightning/pull/212).
15+
1116
### Documentation
1217

1318
### Bug fixes
@@ -18,7 +23,7 @@
1823

1924
This release contains contributions from (in alphabetical order):
2025

21-
Chae-Yeun Park
26+
Ali Asadi, Chae-Yeun Park
2227

2328
---
2429

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

47-
* Update adjointJacobian and VJP methods.
48-
[(#222)](https://github.com/PennyLaneAI/pennylane-lightning/pull/222)
49-
5052
### Documentation
5153

5254
### Bug fixes

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ venv/
22
doc/_build/
33
PennyLane_Lightning.egg-info/
44
build/
5+
Build/
56
BuildBench/
67
BuildTests/
78
dist/

CMakeLists.txt

+6-4
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,13 @@ target_include_directories(pennylane_lightning INTERFACE "pennylane_lightning/sr
7171
#####################################################
7272

7373
pybind11_add_module(lightning_qubit_ops "pennylane_lightning/src/bindings/Bindings.cpp")
74-
target_link_libraries(lightning_qubit_ops PRIVATE lightning_compile_options
75-
lightning_external_libs
76-
lightning_utils
74+
target_link_libraries(lightning_qubit_ops PRIVATE lightning_algorithms
75+
lightning_gates
7776
lightning_simulator
78-
lightning_algorithms)
77+
lightning_utils)
78+
79+
target_link_libraries(lightning_qubit_ops PRIVATE lightning_compile_options
80+
lightning_external_libs)
7981
set_target_properties(lightning_qubit_ops PROPERTIES CXX_VISIBILITY_PRESET hidden)
8082

8183
target_compile_definitions(lightning_qubit_ops PRIVATE VERSION_INFO=${VERSION_STRING})

Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ docs:
5757
clean-docs:
5858
$(MAKE) -C doc clean
5959

60+
.PHONY : test-builtin test-suite test-python coverage test-cpp
6061
test-builtin:
6162
$(PYTHON) -I $(TESTRUNNER)
6263

@@ -117,5 +118,5 @@ endif
117118
.PHONY: check-tidy
118119
check-tidy:
119120
rm -rf ./Build
120-
cmake . -BBuild -DENABLE_CLANG_TIDY=ON -DBUILD_TESTS=1
121+
cmake . -BBuild -DENABLE_CLANG_TIDY=ON -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON
121122
cmake --build ./Build

doc/add_kernel.rst

+37-47
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,52 @@
1+
.. _lightning_add_gate_implementation:
2+
13
Adding a gate implementation
24
############################
35

4-
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:
6+
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:
57

68
.. code-block:: cpp
79
8-
template <class PrecisionT>
10+
// file: MyGateImplementation.hpp
911
struct MyGateImplementation {
10-
constexpr static implemented_gates = {GateOperations::PauliX};
12+
public:
13+
constexpr static std::array implemented_gates = {
14+
GateOperation::PauliX
15+
}; // List of implemented gates
1116
constexpr static kernel_id = KernelType::Mykernel; // Will be discussed below
17+
constexpr static std::string_view = "MyGateImpl"; // Name of your kernel
1218
19+
template <class PrecisionT>
1320
static void applyPauliX(std::complex<PrecisionT>* data,
1421
size_t num_qubits,
1522
const std::vector<size_t>& wires,
1623
[[maybe_unused]] bool inverse) {
1724
/* Write your implementation */
1825
...
1926
}
20-
21-
static void applyPauliY(std::complex<PrecisionT>* data,
22-
size_t num_qubits,
23-
const std::vector<size_t>& wires,
24-
[[maybe_unused]] bool inverse) {
25-
PL_ABORT("MyGateImplementation::applyPauliY is not implemented");
26-
}
27-
28-
/* All other gates */
29-
...
3027
};
3128
32-
Note that all member functions must be defined to prevent compile errors (this requirement may be deprecated in the near future).
33-
34-
Then you can add your gate implementation to Pennylane-Lightning by doing followings:
29+
Then you can add your gate implementation to Pennylane-Lightning. This can be done my modifying two files as:
3530

3631
.. code-block:: cpp
3732
3833
// file: simulator/KernelType.hpp
3934
namespace Pennylane {
40-
enum class KernelType { PI, LM, MyKernel /* This is added */, Unknown };
41-
42-
namespace Constant {
43-
constexpr std::array available_kernels = {
44-
std::pair<KernelType, std::string_view>{KernelType::PI, "PI"},
45-
std::pair<KernelType, std::string_view>{KernelType::LM, "LM"},
46-
/* The following line is added */
47-
std::pair<KernelType, std::string_view>{KernelType::MyKernel, "MyKernel"},
48-
};
35+
enum class KernelType { PI, LM, MyKernel /* This is added */, None };
4936
5037
/* Rest of the file */
38+
5139
} // namespace Pennylane
5240
5341
and
5442

5543
.. code-block:: cpp
5644
57-
// file: simulator/SelectGateOps.hpp
45+
// file: simulator/AvailableKernels.hpp
5846
namespace Pennylane {
59-
...
60-
/* Some code */
61-
62-
template <class fp_t, KernelType kernel> class SelectGateOps {};
63-
64-
template <class fp_t>
65-
class SelectGateOps<fp_t, KernelType::PI> : public GateOperationsPI<fp_t> {};
66-
template <class fp_t>
67-
class SelectGateOps<fp_t, KernelType::LM> : public GateOperationsLM<fp_t> {};
68-
69-
/* Add the following lines */
70-
template <class fp_t>
71-
class SelectGateOps<fp_t, KernelType::MyKernel> : public MyGateImplementation<fp_t> {};
47+
using AvailableKernels = Util::TypeList<GateImplementationsLM,
48+
GateImplementationsPI,
49+
MyGateImplementation /* This is added*/>;
7250
} // namespace Pennylane
7351
7452
@@ -106,10 +84,8 @@ To make your gate implementation default, you need to change ``default_kernel_fo
10684

10785
.. code-block:: cpp
10886
109-
// file: simulator/SelectGateOps.hpp
110-
constexpr std::array<std::pair<GateOperations, KernelType>,
111-
static_cast<int>(GateOperations::END)>
112-
default_kernel_for_ops = {
87+
// file: simulator/Constant.hpp
88+
constexpr std::array default_kernel_for_gates = {
11389
std::pair{GateOperations::PauliX, KernelType::LM},
11490
std::pair{GateOperations::PauliY, KernelType::LM},
11591
...
@@ -119,12 +95,26 @@ to
11995

12096
.. code-block:: cpp
12197
122-
constexpr std::array<std::pair<GateOperations, KernelType>,
123-
static_cast<int>(GateOperations::END)>
124-
default_kernel_for_ops = {
98+
constexpr std::array default_kernel_for_gates = {
12599
std::pair{GateOperations::PauliX, KernelType::MyKernel},
126100
std::pair{GateOperations::PauliY, KernelType::LM},
127101
...
128102
}
129103
130-
will make your implementation as default kernel for ``PauliX`` gate (for all C++ call as well as for the Python binding).
104+
will make your implementation as default kernel for ``PauliX`` gate (for all C++ calls as well as for the Python binding).
105+
106+
Gate generators can also be handled in the same way.
107+
108+
Test your gate implementation
109+
=============================
110+
111+
To test your own kernel implementations, you can go to ``tests/TestKernels.hpp`` and add your implementation.
112+
113+
.. code-block:: cpp
114+
115+
using TestKernels = Pennylane::Util::TypeList<Pennylane::Gates::GateImplementationsLM,
116+
Pennylane::Gates::GateImplementationsPI,
117+
MyGateImplementation /*This is added */>;
118+
119+
It will automatically test your gate implementation.
120+
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.

pennylane_lightning/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
Version number (major.minor.patch[-label])
1717
"""
1818

19-
__version__ = "0.22.0-dev4"
19+
__version__ = "0.22.0-dev5"

pennylane_lightning/lightning_qubit.py

-4
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@
5656

5757

5858
UNSUPPORTED_PARAM_GATES_ADJOINT = (
59-
"MultiRZ",
60-
"IsingXX",
61-
"IsingYY",
62-
"IsingZZ",
6359
"SingleExcitation",
6460
"SingleExcitationPlus",
6561
"SingleExcitationMinus",

pennylane_lightning/src/.clang-tidy

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,-llvmlibc-*,modernize-*,-modernize-use-trailing-return-type,clang-analyzer-cplusplus*,openmp-*,performance-*,portability-*,readability-*,hicpp-signed-bitwise'
2+
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,'
33
WarningsAsErrors: '*'
44
HeaderFilterRegex: '.*'
55
AnalyzeTemporaryDtors: false

pennylane_lightning/src/CMakeLists.txt

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ project(lightning_components LANGUAGES CXX)
55
set(CMAKE_CXX_STANDARD 17)
66

77
option(ENABLE_WARNINGS "Enable warnings" ON)
8+
option(ENABLE_OPENMP "Enable OpenMP" ON)
89

910
if(ENABLE_CLANG_TIDY)
1011
if(NOT DEFINED CLANG_TIDY_BINARY)
@@ -25,8 +26,9 @@ include("${PROJECT_SOURCE_DIR}/../../cmake/process_options.cmake")
2526
###############################################################################
2627
# Include all nested sources directories
2728
###############################################################################
28-
set(COMPONENT_SUBDIRS simulator;
29-
algorithms;
29+
set(COMPONENT_SUBDIRS algorithms;
30+
gates;
31+
simulator;
3032
util;
3133
)
3234
foreach(COMP ${COMPONENT_SUBDIRS})

pennylane_lightning/src/algorithms/AdjointDiff.hpp

+4-88
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
#include <numeric>
1919
#include <stdexcept>
2020
#include <type_traits>
21-
#include <unordered_map>
2221
#include <utility>
2322
#include <variant>
2423
#include <vector>
2524

25+
#include "DynamicDispatcher.hpp"
2626
#include "Error.hpp"
2727
#include "JacobianTape.hpp"
2828
#include "LinearAlgebra.hpp"
@@ -36,70 +36,10 @@ namespace {
3636
using namespace Pennylane;
3737
using namespace Pennylane::Util;
3838

39-
template <class T>
40-
static constexpr auto getP00() -> std::vector<std::complex<T>> {
41-
return {ONE<T>(), ZERO<T>(), ZERO<T>(), ZERO<T>()};
42-
}
43-
44-
template <class T>
45-
static constexpr auto getP11() -> std::vector<std::complex<T>> {
46-
return {ZERO<T>(), ZERO<T>(), ZERO<T>(), ONE<T>()};
47-
}
48-
49-
template <class T = double, class SVType>
50-
void applyGeneratorRX(SVType &sv, const std::vector<size_t> &wires,
51-
const bool adj = false) {
52-
sv.applyPauliX(wires, adj);
53-
}
54-
55-
template <class T = double, class SVType>
56-
void applyGeneratorRY(SVType &sv, const std::vector<size_t> &wires,
57-
const bool adj = false) {
58-
sv.applyPauliY(wires, adj);
59-
}
60-
61-
template <class T = double, class SVType>
62-
void applyGeneratorRZ(SVType &sv, const std::vector<size_t> &wires,
63-
const bool adj = false) {
64-
sv.applyPauliZ(wires, adj);
65-
}
66-
67-
template <class T, class SVType>
68-
void applyGeneratorPhaseShift(SVType &sv, const std::vector<size_t> &wires,
69-
const bool adj = false) {
70-
sv.applyGeneratorPhaseShift(wires, adj);
71-
}
72-
73-
template <class T, class SVType>
74-
void applyGeneratorCRX(SVType &sv, const std::vector<size_t> &wires,
75-
[[maybe_unused]] const bool adj = false) {
76-
sv.applyGeneratorCRX(wires, adj);
77-
}
78-
79-
template <class T, class SVType>
80-
void applyGeneratorCRY(SVType &sv, const std::vector<size_t> &wires,
81-
[[maybe_unused]] const bool adj = false) {
82-
sv.applyGeneratorCRY(wires, adj);
83-
}
84-
85-
template <class T, class SVType>
86-
void applyGeneratorCRZ(SVType &sv, const std::vector<size_t> &wires,
87-
[[maybe_unused]] const bool adj = false) {
88-
sv.applyGeneratorCRZ(wires, adj);
89-
}
90-
91-
template <class T, class SVType>
92-
void applyGeneratorControlledPhaseShift(SVType &sv,
93-
const std::vector<size_t> &wires,
94-
const bool adj = false) {
95-
sv.applyGeneratorControlledPhaseShift(wires, adj);
96-
}
97-
9839
} // namespace
9940
/// @endcond
10041

10142
namespace Pennylane::Algorithms {
102-
10343
/**
10444
* @brief Represent the logic for the adjoint Jacobian method of
10545
* arXiV:2009.02823
@@ -112,29 +52,6 @@ template <class T = double> class AdjointJacobian {
11252
const std::vector<size_t> &,
11353
const bool); // function pointer type
11454

115-
// Holds the mapping from gate labels to associated generator functions.
116-
const std::unordered_map<std::string, GeneratorFunc> generator_map{
117-
{"RX", &::applyGeneratorRX<T, StateVectorManaged<T>>},
118-
{"RY", &::applyGeneratorRY<T, StateVectorManaged<T>>},
119-
{"RZ", &::applyGeneratorRZ<T, StateVectorManaged<T>>},
120-
{"PhaseShift", &::applyGeneratorPhaseShift<T, StateVectorManaged<T>>},
121-
{"CRX", &::applyGeneratorCRX<T, StateVectorManaged<T>>},
122-
{"CRY", &::applyGeneratorCRY<T, StateVectorManaged<T>>},
123-
{"CRZ", &::applyGeneratorCRZ<T, StateVectorManaged<T>>},
124-
{"ControlledPhaseShift",
125-
&::applyGeneratorControlledPhaseShift<T, StateVectorManaged<T>>}};
126-
127-
// Holds the mappings from gate labels to associated generator coefficients.
128-
const std::unordered_map<std::string, T> scaling_factors{
129-
{"RX", -static_cast<T>(0.5)},
130-
{"RY", -static_cast<T>(0.5)},
131-
{"RZ", -static_cast<T>(0.5)},
132-
{"PhaseShift", static_cast<T>(1)},
133-
{"CRX", -static_cast<T>(0.5)},
134-
{"CRY", -static_cast<T>(0.5)},
135-
{"CRZ", -static_cast<T>(0.5)},
136-
{"ControlledPhaseShift", static_cast<T>(1)}};
137-
13855
/**
13956
* @brief Utility method to update the Jacobian at a given index by
14057
* calculating the overlap between two given states.
@@ -365,12 +282,12 @@ template <class T = double> class AdjointJacobian {
365282
* @param adj Indicate whether to take the adjoint of the operation.
366283
* @return T Generator scaling coefficient.
367284
*/
368-
inline auto applyGenerator(StateVectorManaged<T> &sv,
285+
template <class SVType>
286+
inline auto applyGenerator(StateVectorBase<T, SVType> &sv,
369287
const std::string &op_name,
370288
const std::vector<size_t> &wires, const bool adj)
371289
-> T {
372-
generator_map.at(op_name)(sv, wires, adj);
373-
return scaling_factors.at(op_name);
290+
return sv.applyGenerator(op_name, wires, adj);
374291
}
375292

376293
public:
@@ -485,5 +402,4 @@ template <class T = double> class AdjointJacobian {
485402
jac = Transpose(jac, jd.getNumParams(), num_observables);
486403
}
487404
}; // class AdjointJacobian
488-
489405
} // namespace Pennylane::Algorithms

0 commit comments

Comments
 (0)