Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Splitting matrix operations, refactor dispatcher, add a benchmark suite for all gates/generators/matrices #274

Merged
merged 132 commits into from
May 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
9b79196
Add cmake options for coverage
chaeyeunpark Mar 15, 2022
999ff8b
Merge remote-tracking branch 'origin/master' into cpp_coverage
chaeyeunpark Mar 20, 2022
75e2fe4
Fix tests for MSVC
chaeyeunpark Mar 20, 2022
505a2fa
Add bench all gates
chaeyeunpark Mar 21, 2022
e44c9da
Add workflows
chaeyeunpark Mar 21, 2022
245bcb3
Rollback
chaeyeunpark Mar 21, 2022
3a59d91
Auto update version
chaeyeunpark Mar 21, 2022
506a1f5
Fix
chaeyeunpark Mar 21, 2022
c34f99b
Merge branch 'cpp_coverage' of github.com:PennyLaneAI/pennylane-light…
chaeyeunpark Mar 21, 2022
2a231bd
Exclude C++ tests dir itself from codecov
chaeyeunpark Mar 21, 2022
0e6f814
Merge remote-tracking branch 'origin/master' into cpp_coverage
chaeyeunpark Mar 21, 2022
b67c8c8
Update cmake files
chaeyeunpark Mar 21, 2022
5010453
Update workflows
chaeyeunpark Mar 21, 2022
5ce3de1
Merge remote-tracking branch 'origin/master' into cpp_coverage
chaeyeunpark Mar 21, 2022
d1dd89a
Auto update version
chaeyeunpark Mar 21, 2022
60cb40c
Turn off openmp for windows
chaeyeunpark Mar 21, 2022
5461255
Update path format
chaeyeunpark Mar 21, 2022
a1baff4
Windows path update
chaeyeunpark Mar 21, 2022
1997175
Change to Release
chaeyeunpark Mar 22, 2022
e6c6fe2
Test codecov upload
chaeyeunpark Mar 22, 2022
1d5f492
Fix for opencppcoverage
chaeyeunpark Mar 22, 2022
71ebb65
Fix MSVC
chaeyeunpark Mar 22, 2022
d9a9d78
Fix codecov uploader
chaeyeunpark Mar 22, 2022
82594ea
Remove unsupported option for codecov uploader v1
chaeyeunpark Mar 22, 2022
4dd9db4
Renamed yaml file
chaeyeunpark Mar 22, 2022
7a69272
Set fetch-depth for codecov
chaeyeunpark Mar 22, 2022
1246d7c
Add ENABLE_BLAS for OpenBLAS CI
chaeyeunpark Mar 22, 2022
b6d6ffa
Merge remote-tracking branch 'origin/master' into benchmark_all_gates
chaeyeunpark Mar 22, 2022
68a1ab3
Merge branch 'master' into cpp_coverage
maliasadi Mar 22, 2022
e483032
Auto update version
chaeyeunpark Mar 22, 2022
c7185f9
Split applying matrix from gate operation
chaeyeunpark Mar 22, 2022
6d9eb08
Fix for some tests
chaeyeunpark Mar 22, 2022
107d1c3
Fixing benchmarks
chaeyeunpark Mar 22, 2022
90de964
C++ code works
chaeyeunpark Mar 22, 2022
4cb6337
Trigger CI
chaeyeunpark Mar 22, 2022
ef59a49
Adding benchmark tools
chaeyeunpark Mar 22, 2022
461b300
Merge remote-tracking branch 'origin/master' into benchmark_all_gates
chaeyeunpark Mar 23, 2022
1fd37aa
Add matrix to compare kernel tests
chaeyeunpark Mar 23, 2022
99e5b41
Trigger CI
chaeyeunpark Mar 23, 2022
e105279
Auto update version
chaeyeunpark Mar 23, 2022
6760a0a
Merge remote-tracking branch 'origin/master' into cpp_coverage
chaeyeunpark Mar 23, 2022
97f2cfb
Auto update version
chaeyeunpark Mar 23, 2022
95dc47c
Fix coverage of Error.hpp
mlxd Mar 23, 2022
7bc4840
Auto update version
chaeyeunpark Mar 23, 2022
e7f562c
Merge branch 'master' into cov_report
mlxd Mar 23, 2022
e2a0a41
Merge remote-tracking branch 'origin/master' into benchmark_all_gates
chaeyeunpark Mar 23, 2022
391f495
Python cannot select kernels anymore
chaeyeunpark Mar 23, 2022
09f0d76
Move Error tests to separate file
mlxd Mar 23, 2022
3cb1ee6
Merge branch 'cov_report' of github.com:PennyLaneAI/pennylane-lightni…
mlxd Mar 23, 2022
a056716
Trigger CI
mlxd Mar 23, 2022
14a3b91
Update for coverage
chaeyeunpark Mar 23, 2022
c100c55
Fix
chaeyeunpark Mar 23, 2022
ccdd28a
Fix
chaeyeunpark Mar 23, 2022
2c20b40
Format
chaeyeunpark Mar 23, 2022
3e9bfe0
Fix for tidy
chaeyeunpark Mar 23, 2022
63d31ce
Remove unnecessary line
chaeyeunpark Mar 23, 2022
2ddbd6e
Fix codecov w/ lightning_qubit.py
maliasadi Mar 23, 2022
fd05532
Update benchmark
chaeyeunpark Mar 24, 2022
a6824a1
Add LinearAlgebra tests
maliasadi Mar 24, 2022
73add79
Update VJP tests
maliasadi Mar 24, 2022
187b61b
Update AdjDiff
maliasadi Mar 24, 2022
04ac454
Update
maliasadi Mar 24, 2022
de1e878
Fix Tidy
maliasadi Mar 24, 2022
4d671a4
Fix for codefix
chaeyeunpark Mar 24, 2022
41e5624
one last try...
maliasadi Mar 24, 2022
0c3b49a
Small fix for clang
chaeyeunpark Mar 24, 2022
b955110
Add benchmark matrix
chaeyeunpark Mar 24, 2022
2714b74
Manual update version
chaeyeunpark Mar 24, 2022
16b84ab
Test on a new branch
chaeyeunpark Mar 24, 2022
80ba863
Fix for windows
chaeyeunpark Mar 24, 2022
f78769c
Fix matrix tests
chaeyeunpark Mar 24, 2022
4e810e3
Update codecov setup
chaeyeunpark Mar 24, 2022
a04a99b
Update codecov report set-up
chaeyeunpark Mar 24, 2022
636513d
Merge branch 'cov_report' of github.com:PennyLaneAI/pennylane-lightni…
chaeyeunpark Mar 24, 2022
1d0a580
Coverage applyMatrix
chaeyeunpark Mar 24, 2022
f6c80fb
Trigger CI
chaeyeunpark Mar 24, 2022
2e8a5c5
Trigger CI
chaeyeunpark Mar 24, 2022
1c3209f
Fix matrix inverse test
chaeyeunpark Mar 24, 2022
c659a89
Update codecov
mlxd Mar 24, 2022
6107af4
Upgrade codecov version. Version 1 is deprecated a mont ago...
chaeyeunpark Mar 24, 2022
0717ab7
Upgrade codecov uploader version. Version 1 was deprecated a month ag…
chaeyeunpark Mar 24, 2022
8e33756
Merge remote-tracking branch 'origin1/cov_report' into cov_report
mlxd Mar 24, 2022
af88fb9
Add some more tests
chaeyeunpark Mar 25, 2022
b7308ec
Update README.md
chaeyeunpark Mar 25, 2022
f3c6fcc
Fix a test
chaeyeunpark Mar 25, 2022
a5e775e
Add more test
chaeyeunpark Mar 25, 2022
2fdea13
Fix for codefactor
chaeyeunpark Mar 25, 2022
a323c35
Fix documents
chaeyeunpark Mar 25, 2022
cd75e10
Merge branch 'cov_report' into splitting_matrix_ops
chaeyeunpark Mar 25, 2022
ab29440
Add a test
chaeyeunpark Mar 26, 2022
efe55d6
Fix
chaeyeunpark Mar 26, 2022
3582243
Fix
chaeyeunpark Mar 26, 2022
1665593
Use dynamic dispatcher instead of TMP in a test
chaeyeunpark Mar 26, 2022
1217d64
Fux for codecov
chaeyeunpark Mar 26, 2022
b635159
Fix for codecov
chaeyeunpark Mar 26, 2022
bd66569
Small fix applyMatrix exception
chaeyeunpark Mar 26, 2022
a0cf150
Merge remote-tracking branch 'origin/master' into splitting_matrix_ops
chaeyeunpark Mar 28, 2022
96826e2
Auto update version
chaeyeunpark Mar 28, 2022
0ad4944
Temporary fix for black
chaeyeunpark Mar 28, 2022
dc911db
Update docstring
chaeyeunpark Mar 28, 2022
67067a5
Update docstring
chaeyeunpark Mar 28, 2022
0054c14
Fix packed_bytes
chaeyeunpark Mar 29, 2022
9b830f8
Merge remote-tracking branch 'origin/master' into splitting_matrix_ops
chaeyeunpark Mar 30, 2022
cbee047
Update benchmark CI
chaeyeunpark Mar 30, 2022
801f253
Apply suggestions from code review
chaeyeunpark Mar 30, 2022
3aaf77f
Update cmake
chaeyeunpark Mar 30, 2022
6ae0042
Update pennylane_lightning/_serialize.py
chaeyeunpark Apr 11, 2022
8cfae7a
Fix benchmark CMake
chaeyeunpark Apr 11, 2022
ac231cc
Update docstring
chaeyeunpark Apr 11, 2022
3a9024f
Update kernels
chaeyeunpark Apr 11, 2022
2984d6c
Merge branch 'splitting_matrix_ops' of github.com:PennyLaneAI/pennyla…
chaeyeunpark Apr 12, 2022
cbaf1b3
Format
chaeyeunpark Apr 12, 2022
eb73d98
Fix
chaeyeunpark Apr 12, 2022
4015624
Updated macOS version for CI
chaeyeunpark Apr 12, 2022
eec030a
Merge remote-tracking branch 'origin/master' into splitting_matrix_ops
chaeyeunpark Apr 20, 2022
39bee05
Apply suggestions from code review
chaeyeunpark Apr 20, 2022
be0e467
Auto update version
chaeyeunpark Apr 20, 2022
de98b1d
Merge branch 'master' into splitting_matrix_ops
chaeyeunpark Apr 21, 2022
795c3fe
Merge branch 'splitting_matrix_ops' of github.com:PennyLaneAI/pennyla…
chaeyeunpark Apr 21, 2022
aafdc5f
Fix
chaeyeunpark Apr 21, 2022
dc46d14
Apply suggestions from code review
chaeyeunpark Apr 21, 2022
5200137
Merge remote-tracking branch 'origin/master' into splitting_matrix_ops
chaeyeunpark Apr 27, 2022
c2b2147
Merge branch 'master' into splitting_matrix_ops
chaeyeunpark May 2, 2022
78be590
Auto update version
chaeyeunpark May 2, 2022
e6230eb
Update pennylane_lightning/src/gates/DynamicDispatcher.cpp
chaeyeunpark May 3, 2022
f1053fe
Retrigger CI
chaeyeunpark May 3, 2022
988090c
Merge remote-tracking branch 'origin/master' into splitting_matrix_ops
chaeyeunpark May 6, 2022
a3fdcf5
Auto update version
chaeyeunpark May 6, 2022
a2eed3d
Trigger CI
chaeyeunpark May 6, 2022
86f4c36
Update benchmark
chaeyeunpark May 6, 2022
1fb5bd7
Update doc
chaeyeunpark May 6, 2022
2bd3796
Update changelog
chaeyeunpark May 6, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

### Improvements

* Split matrix operations, refactor dispatch mechanisms, and add a benchmark suits.
[(#274)](https://github.com/PennyLaneAI/pennylane-lightning/pull/274)

### Documentation

* Use the centralized [Xanadu Sphinx Theme](https://github.com/XanaduAI/xanadu-sphinx-theme)
Expand All @@ -18,7 +21,7 @@

This release contains contributions from (in alphabetical order):

Mikhail Andrenkov
Mikhail Andrenkov, Chae-Yeun Park

---

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Install dependencies
run:
python -m pip install --upgrade pip
pip install black
pip install click==8.0.4 black

- uses: actions/checkout@v2

Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/tests_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,9 @@ jobs:
- name: Build and run gbenchmark
run: |
cmake pennylane_lightning/src/ -BBuildGBench -DBUILD_BENCHMARKS=ON -DENABLE_BLAS=ON -DCMAKE_BUILD_TYPE=Release
cmake --build ./BuildGBench --target utils apply_operations apply_multirz
cmake --build ./BuildGBench
./BuildGBench/benchmarks/utils
./BuildGBench/benchmarks/apply_operations
./BuildGBench/benchmarks/apply_multirz

pythontests:
name: Python tests
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ PennyLane_Lightning.egg-info/
build/
Build/
BuildBench/
BuildGBench/
BuildTests/
dist/
tests/__pycache__/
Expand All @@ -19,6 +20,7 @@ doc/code/
cpptests
*.o

.cache/*
.vscode/*
.ycm_extra_conf.py
/.vs
Expand Down
13 changes: 3 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,11 @@ test-cpp-omp:
cmake --build ./BuildTests --target runner
cmake --build ./BuildTests --target test

.PHONY: benchmark
benchmark:
cmake --build BuildBench --target clean || true
rm -rf ./BuildBench/CMakeCache.txt ./BuildBench/compiler_info.txt ./BuildBench/run_gate_benchmark.sh
cmake $(LIGHTNING_CPP_DIR) -BBuildBench -DBUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_AVX=ON
cmake --build ./BuildBench

.PHONY: gbenchmark
gbenchmark:
rm -rf ./BuildGBench
cmake $(LIGHTNING_CPP_DIR) -BBuildGBench -DBUILD_BENCHMARKS=ON -DENABLE_OPENMP=ON -DENABLE_BLAS=ON -DCMAKE_BUILD_TYPE=Release
cmake --build ./BuildGBench --target utils apply_operations apply_multirz
cmake --build ./BuildGBench

.PHONY: format format-cpp format-python
format: format-cpp format-python
Expand All @@ -125,5 +118,5 @@ endif
.PHONY: check-tidy
check-tidy:
rm -rf ./Build
cmake . -BBuild -DENABLE_CLANG_TIDY=ON -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON
cmake --build ./Build
cmake . -BBuild -DENABLE_CLANG_TIDY=ON -DBUILD_TESTS=ON
cmake --build ./Build
Binary file added doc/_static/benchmark/PauliX.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/_static/benchmark/RX.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed doc/_static/benchmark/plot_PauliX.png
Binary file not shown.
Binary file removed doc/_static/benchmark/plot_RX.png
Binary file not shown.
12 changes: 1 addition & 11 deletions doc/add_kernel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,6 @@ Now you can call your kernel functions in C++.
// call using the dynamic dispatcher
sv.applyOperation(KernelType::MyKernel, "PauliX", /*wires=*/{0}, /*inverse=*/false);

To export your gate implementation to python, you also need to add your kernel to ``kernels_to_pyexport``:

.. code-block:: cpp

// file: simulator/KernelType.hpp
[[maybe_unused]] constexpr std::array kernels_to_pyexport = {
KernelType::PI, KernelType::LM, KernelType::Mykernel /* This is added */
};

Then you can find ``PauliX_MyKernel`` function in ``lightning_qubit_ops`` Python module.

Still, note that your gate implementation is not a default implementation for ``PauliX`` gate yet, i.e.,

Expand All @@ -84,7 +74,7 @@ To make your gate implementation default, you need to change ``default_kernel_fo

.. code-block:: cpp

// file: simulator/Constant.hpp
// file: gates/Constant.hpp
constexpr std::array default_kernel_for_gates = {
std::pair{GateOperations::PauliX, KernelType::LM},
std::pair{GateOperations::PauliY, KernelType::LM},
Expand Down
35 changes: 21 additions & 14 deletions doc/benchmark.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,43 @@ You can benchmark different gate implementations inside the project.

.. code-block:: console

$ make benchmark
$ cd BuildBench
$ make gbenchmark
$ cd BuildGBench

Inside the directory, you can see ``run_gate_benchmark.sh``. You can benchmark a specific kernel implementation for a gate by providing arguments.
Currently, we have two different kernels in ``Pennylane-Lightning`` named ``PI`` and ``LM``. For difference between two kernels, see the documents :cpp:class:`Pennylane::GateOperationsPI` and :cpp:class:`Pennylane::GateOperationsLM`.
For example, you can compare benchmark results for ``PauliX`` gate with ``KernelType::PI`` and ``KernelType::LM`` by running the following commands:
Then you can benchmark all gate operations in all kernels by running the script.

.. code-block:: console

$ ./run_gate_benchmark.sh PI PauliX
$ ./run_gate_benchmark.sh LM PauliX

The benchmark results will be written in ``res_{COMPILER}_{VERSION}`` subdirectory. For example, if you use GCC version 9.3.0, the directory name will be ``res_GNU_9.3.0``.
$ ./benchmarks/benchmark_all.sh

The results will be recorded in ``bench_result.json`` file.
You can then plot the results for a specific gate with

.. code-block:: console

$ ./plot_gate_benchmark res_GNU_9.3.0 PauliX
$ ./benchmarks/plot_gate_benchmark.py ./bench_result.json

It will create a plot for each gate operation comparing performance of kernels and floating point types. The plots can be found in ``plots`` subdirectory.

One can also choose a specific datatype by providing an option:

.. code-block:: console

$ ./benchmarks/plot_gate_benchmark.py --precision float ./bench_result.json # Results for std::complex<float>
$ ./benchmarks/plot_gate_benchmark.py --precision double ./bench_result.json # Results for std::complex<double>


Currently, we have two different kernels in ``Pennylane-Lightning`` named ``PI`` and ``LM``. For difference between two kernels, see the documents :cpp:class:`Pennylane::Gates::GateImplementationsPI` and :cpp:class:`Pennylane::Gates::GateImplementationsLM`.

You should change the second argument to your result directory name. Example outputs are as below:
Here are some example plots:

.. image:: ./_static/benchmark/plot_PauliX.png
.. image:: ./_static/benchmark/PauliX.png
:width: 600
:alt: Benchmark result for PauliX gate
:align: center

.. image:: ./_static/benchmark/plot_RX.png
.. image:: ./_static/benchmark/RX.png
:width: 600
:alt: Benchmark result for RX gate
:align: center

It shows the LM kernel is :math:`\sim 2` times faster for the PauliX gate (for all number of qubits :math:`N`) but is slightly slower for the RX gate when :math:`N \leq 22`.
15 changes: 1 addition & 14 deletions pennylane_lightning/_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,11 @@
ObsStructC64,
StateVectorC128,
ObsStructC128,
DEFAULT_KERNEL_FOR_OPS,
)
except ImportError:
pass


def _is_lightning_gate(gate_name):
"""Returns True if the gate (besides Matrix) is implemented
and exported from lightning.

Args:
gate_name (str): the name of gate
"""
if gate_name == "Matrix":
return False
return gate_name in DEFAULT_KERNEL_FOR_OPS


def _obs_has_kernel(obs: Observable) -> bool:
"""Returns True if the input observable has a supported kernel in the C++ backend.

Expand Down Expand Up @@ -171,7 +158,7 @@ def _serialize_ops(
name = single_op.name if not is_inverse else single_op.name[:-4]
names.append(name)

if not _is_lightning_gate(name):
if not hasattr(StateVectorC128, name):
params.append([])
mats.append(qml.matrix(single_op))

Expand Down
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.24.0-dev4"
__version__ = "0.24.0-dev5"
29 changes: 4 additions & 25 deletions pennylane_lightning/lightning_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,9 @@
StateVectorC128,
AdjointJacobianC128,
VectorJacobianProductC128,
DEFAULT_KERNEL_FOR_OPS,
EXPORTED_KERNEL_OPS,
)

from ._serialize import _serialize_obs, _serialize_ops, _is_lightning_gate
from ._serialize import _serialize_obs, _serialize_ops

CPP_BINARY_AVAILABLE = True
except ModuleNotFoundError:
Expand Down Expand Up @@ -98,9 +96,6 @@ class LightningQubit(DefaultQubit):

Args:
wires (int): the number of wires to initialize the device with
kernel_for_ops (dict): Optional argument which kernel to run for a gate operation.
For example, if {'PauliX': 'LM', 'RX': 'PI'} is passed, the less memory (LM) kernel
is used for PauliX whereas precomputed indices (PI) kernel is used for RX.
shots (int): How many times the circuit should be evaluated (or sampled) to estimate
the expectation values. Defaults to ``None`` if not specified. Setting
to ``None`` results in computing statistics like expectation values and
Expand All @@ -115,19 +110,7 @@ class LightningQubit(DefaultQubit):
_CPP_BINARY_AVAILABLE = True
operations = _remove_snapshot_from_operations(DefaultQubit.operations)

def __init__(self, wires, *, kernel_for_ops=None, shots=None, batch_obs=False):
self._kernel_for_ops = DEFAULT_KERNEL_FOR_OPS
if kernel_for_ops is not None:
if not isinstance(kernel_for_ops, dict):
raise ValueError("Argument kernel_for_ops must be a dictionary.")

for gate_op, kernel in kernel_for_ops.items():
if (kernel, gate_op) not in EXPORTED_KERNEL_OPS:
raise ValueError(
f"The given kernel {kernel} does not implement {gate_op} gate."
)
self._kernel_for_ops[gate_op] = kernel

def __init__(self, wires, *, shots=None, batch_obs=False):
super().__init__(wires, shots=shots)
self._batch_obs = batch_obs

Expand Down Expand Up @@ -211,17 +194,13 @@ def apply_lightning(self, state, operations, dtype=np.complex128):
if o.base_name in skipped_ops:
continue
name = o.name.split(".")[0] # The split is because inverse gates have .inv appended
if _is_lightning_gate(name):
kernel = self._kernel_for_ops[name]
method = getattr(sim, f"{name}_{kernel}".format(), None)
else:
method = None
method = getattr(sim, name, None)

wires = self.wires.indices(o.wires)

if method is None:
# Inverse can be set to False since qml.matrix(o) is already in inverted form
method = getattr(sim, "applyMatrix_{}".format(self._kernel_for_ops["Matrix"]))
method = getattr(sim, "applyMatrix")
try:
method(qml.matrix(o), wires, False)
except AttributeError: # pragma: no cover
Expand Down
Loading