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

Add C++ adjoint diff methods #136

Merged
merged 76 commits into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
fbdeedd
Add inner product routine with STL and BLAS options
mlxd Aug 19, 2021
a26cb1e
Add prelim adj diff implementation
mlxd Aug 19, 2021
b0d49a2
Refactor build-system structure to enable better extensibility
mlxd Aug 20, 2021
adbc267
Add explicit build support for algorithms
mlxd Aug 20, 2021
88a1595
Clean Util cmake
mlxd Aug 20, 2021
ec9db68
Add explicit overload resolution to innerProd
mlxd Aug 20, 2021
d47eb2c
Add build support for AdjointDiff
mlxd Aug 20, 2021
ca950b3
Update testing for new utils
mlxd Aug 20, 2021
409759f
Ensure formatting is run in nested dirs
mlxd Aug 20, 2021
b955bee
Add cout functionality for StateVector
mlxd Aug 20, 2021
140f950
Add dot for conjugated and non conjugated data
mlxd Aug 20, 2021
cf07cc9
Begin dev of adjoint diff tests
mlxd Aug 20, 2021
9e8ae62
Add additional tests to util suite
mlxd Aug 20, 2021
aa19e98
Attempt debugging of multi-obs issues
mlxd Aug 20, 2021
35ba63d
Merge branch master into 7072_adj_diff
mlxd Aug 23, 2021
edf6b1b
Ensure FPIC on for generated .a libs
mlxd Aug 23, 2021
4ea6c3d
Fix native flag in CMake
mlxd Aug 23, 2021
5859083
Ensure propagation of flags to lower dirs
mlxd Aug 23, 2021
1d456fa
Update build flags
mlxd Aug 23, 2021
3e91d07
Add additional testing
mlxd Aug 24, 2021
1a12eb9
Update tests
mlxd Aug 25, 2021
2317a94
Encapsulate ops and obs data for Python serialization
mlxd Aug 25, 2021
2216b51
Restructure the obs and ops data for adjoint calcs
mlxd Aug 25, 2021
f5e029a
Lint and add defines
mlxd Aug 25, 2021
ca706c2
Fix testing binary location
mlxd Aug 25, 2021
81d41ba
Merge branch 'master' into 7072_adj_diff
mlxd Aug 25, 2021
5df74a0
Attempt to appease codefactor
mlxd Aug 25, 2021
9842bb4
Merge branch '7072_adj_diff' of github.com:PennyLaneAI/pennylane-ligh…
mlxd Aug 25, 2021
f154807
Fix memory alignment errors on output for adj
mlxd Aug 26, 2021
09fb87d
Fix broken tests due to MVP
mlxd Aug 26, 2021
75530bd
Add adjoint method to Python frontend (#137)
trbromley Aug 27, 2021
1cb2fcd
Merge branch '7072_adj_diff' of github.com:PennyLaneAI/pennylane-ligh…
mlxd Aug 27, 2021
1743fc4
Add support for statevector with own managed memory
mlxd Aug 27, 2021
8f1a585
Add param gateset tests for SVM
mlxd Aug 27, 2021
ebcf216
Fixed memory access issues with memory managed statevector
mlxd Aug 27, 2021
c1a7c27
Fix C++ adjoint calls
mlxd Aug 27, 2021
bf181e1
Update parallelisation using OpenMP
mlxd Aug 27, 2021
09f9e4b
Update Python and run black
mlxd Aug 27, 2021
31864cc
Fix serialisation for tensor expvals
mlxd Aug 30, 2021
224bc9a
Ensure statevector is linear 1D array before offloading to C++
mlxd Aug 30, 2021
1e85c63
Add repr bindings for improved debugging
mlxd Aug 30, 2021
ff4cee3
Enable OpenMP for observables
mlxd Aug 30, 2021
bf2de2a
Ensure OpenMP is optional requirement
mlxd Aug 30, 2021
3b10aca
Fix vector stream formatting
mlxd Aug 30, 2021
ac01781
Move and format bindings
mlxd Aug 30, 2021
2756cdf
Aim to appease codefactor
mlxd Aug 30, 2021
c705157
Offload StateVectorManaged to separate file
mlxd Aug 30, 2021
0cc4db3
Readd missing file
mlxd Aug 30, 2021
26a9607
Avoid loading cmath before math defines for Windows
mlxd Aug 30, 2021
c02d21c
Add defines to compiler rather than source
mlxd Aug 30, 2021
9cea641
Add guards for C++ binding utility modules import
mlxd Aug 30, 2021
707c0e8
Add comments to AdjointDiff to silence codefactor
mlxd Aug 30, 2021
30bd6b4
Add ostream for statevectors
mlxd Aug 31, 2021
fa81fc5
Add ostream for vector and sets
mlxd Aug 31, 2021
ac8b857
Improve performance of Adj method
mlxd Aug 31, 2021
101b31a
Ensure set passed to C++ layer
mlxd Aug 31, 2021
f1b38c6
Simplify call structure
mlxd Sep 1, 2021
3409828
Tidy loop structure
mlxd Sep 1, 2021
11d62d4
Update Obs class for float and complex data
mlxd Sep 1, 2021
ae5d41f
Track updated Obs structure
mlxd Sep 1, 2021
61ccffc
Add variant support for observables from Python
mlxd Sep 1, 2021
3626f2f
Allow support for "Hermitian" observables
mlxd Sep 1, 2021
05bdacb
Add support for mixing of observable types
mlxd Sep 2, 2021
f95aa02
Fix serialization tests for adjoint method (#141)
trbromley Sep 3, 2021
380135a
Fix compilation
mlxd Sep 3, 2021
bdab848
Add new integration test for adjoint jacobian (#142)
trbromley Sep 10, 2021
e0c4006
Update pennylane_lightning/src/algorithms/AdjointDiff.hpp
mlxd Sep 13, 2021
2ae4d7e
Update pennylane_lightning/src/simulator/StateVectorManaged.hpp
mlxd Sep 13, 2021
cf5ac07
Update pennylane_lightning/src/util/Error.hpp
mlxd Sep 13, 2021
9003139
Update pennylane_lightning/src/algorithms/AdjointDiff.hpp
mlxd Sep 13, 2021
7c51f2c
Update pennylane_lightning/src/algorithms/AdjointDiff.hpp
mlxd Sep 13, 2021
e6f99d9
Fix typos and remove comments
mlxd Sep 13, 2021
189a837
Update changelog
mlxd Sep 13, 2021
0441afd
Fix codecov reduction
mlxd Sep 13, 2021
04ee646
Trigger build
mlxd Sep 13, 2021
e1d569f
CodeCov fix
mlxd Sep 13, 2021
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
13 changes: 13 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@

### Improvements

* A new state-vector class `StateVectorManaged` was added, enabling memory use to be bound to
statevector lifetime.
[(136)](https://github.com/PennyLaneAI/pennylane-lightning/pull/136)

* The repository now has a well-defined component hierarchy, allowing each indepedent unit to be
compiled and linked separately.
[(136)](https://github.com/PennyLaneAI/pennylane-lightning/pull/136)

* PennyLane-Lightning now has support for the adjoint Jacobian method of http://arxiv.org/abs/2009.02823.
[(136)](https://github.com/PennyLaneAI/pennylane-lightning/pull/136)
Comment on lines +20 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me this is a major new feature 🚀 🎉 We can probably move it up during release 😁


* PennyLane-Lightning can now be installed without compiling its C++ binaries and will fall back
to using the `default.qubit` implementation. Skipping compilation is achieved by setting the
`SKIP_COMPILATION` environment variable, e.g., Linux/MacOS: `export SKIP_COMPILATION=True`,
Expand All @@ -32,6 +43,8 @@

### Bug fixes

* An indexing error in the CRY gate is fixed. [(#136)](https://github.com/PennyLaneAI/pennylane-lightning/pull/136)

* Column-major data in numpy is now correctly converted to row-major upon pass to the C++ layer.
[(#126)](https://github.com/PennyLaneAI/pennylane-lightning/pull/126)

Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
cmake . -BBuild -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=1
cmake --build ./Build
mkdir -p ./Build/tests/results
./Build/tests/runner --order lex --reporter junit --out ./Build/tests/results/report.xml
./Build/pennylane_lightning/src/tests/runner --order lex --reporter junit --out ./Build/tests/results/report.xml
trbromley marked this conversation as resolved.
Show resolved Hide resolved

- name: Upload test results
uses: actions/upload-artifact@v2
Expand Down Expand Up @@ -74,6 +74,8 @@ jobs:
cd main
python -m pip install --upgrade pip
pip install -r requirements.txt
pip uninstall pennylane -y
pip install git+https://github.com/PennyLaneAI/pennylane.git

- name: Install lightning.qubit device
run: |
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/tests_without_binary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ jobs:
cd main
python -m pip install --upgrade pip
pip install -r requirements.txt
pip uninstall pennylane -y
pip install git+https://github.com/PennyLaneAI/pennylane.git

- name: Install lightning.qubit device
run: |
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/wheel_macos_x86_64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ env:
# MacOS specific build settings
CIBW_BEFORE_ALL_MACOS: |
brew uninstall --force oclint
brew install gcc libomp
brew install llvm libomp

# Python build settings
CIBW_BEFORE_BUILD: |
Expand Down Expand Up @@ -53,6 +53,8 @@ jobs:
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_ARCHS_MACOS: ${{matrix.arch}}
CC: /usr/local/opt/llvm/bin/clang
CXX: /usr/local/opt/llvm/bin/clang++
Comment on lines +56 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the CC option for C (i.e., the language)? Do we need it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, and you are right. Removing CC should be fine (though I'll test it out). There may be a way to avoid use of this too, though I must check this out first.


- uses: actions/upload-artifact@v2
if: github.ref == 'refs/heads/master'
Expand Down
21 changes: 11 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ message(STATUS "pennylane_lightning version ${VERSION_STRING}")
set(PROJECT_VERSION ${VERSION_STRING})

set(CMAKE_CXX_STANDARD 17) # At least C++17 is required
find_package(OpenMP REQUIRED) # find OpenMP

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
Expand All @@ -39,7 +38,12 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(pybind11)

add_library(pennylane_lightning SHARED "pennylane_lightning/src/StateVector.cpp")
add_subdirectory(pennylane_lightning/src)

add_library(pennylane_lightning INTERFACE)
target_link_libraries(pennylane_lightning INTERFACE lightning_utils
lightning_simulator
lightning_algorithms)
target_include_directories(pennylane_lightning INTERFACE "pennylane_lightning/src")

add_library(external_dependency INTERFACE)
Expand All @@ -50,24 +54,21 @@ if ("$ENV{USE_OPENBLAS}" OR "${USE_OPENBLAS}")
target_compile_options(external_dependency INTERFACE "-DOPENBLAS=1")
endif()

pybind11_add_module(lightning_qubit_ops "pennylane_lightning/src/StateVector.cpp"
"pennylane_lightning/src/Bindings.cpp")
target_link_libraries(lightning_qubit_ops PRIVATE external_dependency)
pybind11_add_module(lightning_qubit_ops "pennylane_lightning/src/bindings/Bindings.cpp")
target_link_libraries(lightning_qubit_ops PRIVATE pennylane_lightning external_dependency)
set_target_properties(lightning_qubit_ops PROPERTIES CXX_VISIBILITY_PRESET hidden)

target_link_libraries(lightning_qubit_ops PRIVATE OpenMP::OpenMP_CXX)
target_compile_options(lightning_qubit_ops PRIVATE "$<$<CONFIG:RELEASE>:-W>")
target_compile_options(lightning_qubit_ops PRIVATE "$<$<CONFIG:DEBUG>:-Wall>")
target_compile_definitions(lightning_qubit_ops PRIVATE VERSION_INFO=${VERSION_STRING})

if(ENABLE_NATIVE)
message(STATUS "ENABLE_NATIVE is ON. Use -march=native for lightning_qubit_ops.")
target_compile_options(pennylane_lightning PRIVATE -march=native)
message(STATUS "ENABLE_NATIVE is ON. Using -march=native")
add_compile_options(-march=native)
target_compile_options(pennylane_lightning INTERFACE -march=native)
target_compile_options(lightning_qubit_ops PRIVATE -march=native)
endif()


if (BUILD_TESTS)
enable_testing()
add_subdirectory("pennylane_lightning/src/tests" "tests")
endif()
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ test-cpp:
rm -rf ./BuildTests
cmake . -BBuildTests -DBUILD_TESTS=1
cmake --build ./BuildTests
./BuildTests/tests/runner
./BuildTests/pennylane_lightning/src/tests/runner

.PHONY: format
format:
ifdef check
./bin/format --check pennylane_lightning/src tests
./bin/format --check pennylane_lightning/src/* tests
else
./bin/format pennylane_lightning/src tests
./bin/format pennylane_lightning/src/* tests
endif
148 changes: 148 additions & 0 deletions pennylane_lightning/_serialize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Copyright 2021 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
r"""
Helper functions for serializing quantum tapes.
"""
from typing import List, Tuple

import numpy as np
from pennylane import BasisState, Hadamard, Projector, QubitStateVector, Rot
from pennylane.grouping import is_pauli_word
from pennylane.operation import Observable, Tensor
from pennylane.tape import QuantumTape

try:
from .lightning_qubit_ops import StateVectorC128, ObsStructC128
except ImportError:
pass


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

Args:
obs (Observable): the input observable

Returns:
bool: indicating whether ``obs`` has a dedicated kernel in the backend
"""
if is_pauli_word(obs):
return True
if isinstance(obs, (Hadamard, Projector)):
return True
if isinstance(obs, Tensor):
return all(_obs_has_kernel(o) for o in obs.obs)
return False


def _serialize_obs(tape: QuantumTape, wires_map: dict) -> List:
"""Serializes the observables of an input tape.

Args:
tape (QuantumTape): the input quantum tape
wires_map (dict): a dictionary mapping input wires to the device's backend wires

Returns:
list(ObsStructC128): A list of observable objects compatible with the C++ backend
"""
obs = []

for o in tape.observables:
is_tensor = isinstance(o, Tensor)

wires = []

if is_tensor:
for o_ in o.obs:
wires_list = o_.wires.tolist()
w = [wires_map[w] for w in wires_list]
wires.append(w)
else:
wires_list = o.wires.tolist()
w = [wires_map[w] for w in wires_list]
wires.append(w)

name = o.name if is_tensor else [o.name]

params = []

if not _obs_has_kernel(o):
if is_tensor:
for o_ in o.obs:
if not _obs_has_kernel(o_):
params.append(o_.matrix.ravel().astype(np.complex128))
else:
params.append([])
else:
params.append(o.matrix.ravel().astype(np.complex128))

ob = ObsStructC128(name, params, wires)
obs.append(ob)

return obs


def _serialize_ops(
tape: QuantumTape, wires_map: dict
) -> Tuple[List[List[str]], List[np.ndarray], List[List[int]], List[bool], List[np.ndarray]]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
) -> Tuple[List[List[str]], List[np.ndarray], List[List[int]], List[bool], List[np.ndarray]]:
) -> Tuple[Tuple[List[List[str]], List[np.ndarray], List[List[int]], List[bool], List[np.ndarray]], bool]:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this should be fine, I wonder will it mess with the conversion to C++ (though I'd imagine pybind is clever enough that we do need to be explicit).

"""Serializes the operations of an input tape.

The state preparation operations are not included.

Args:
tape (QuantumTape): the input quantum tape
wires_map (dict): a dictionary mapping input wires to the device's backend wires

Returns:
Tuple[list, list, list, list, list]: A serialization of the operations, containing a list
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Tuple[list, list, list, list, list]: A serialization of the operations, containing a list
Tuple[Tuple[list, list, list, list, list], bool]: A serialization of the operations as a
tuple of lists and a flag indicating whether non-default state preparation is used in the
tape.

of operation names, a list of operation parameters, a list of observable wires, a list of
inverses, and a list of matrices for the operations that do not have a dedicated kernel.
"""
names = []
params = []
wires = []
inverses = []
mats = []

uses_stateprep = False

for o in tape.operations:
if isinstance(o, (BasisState, QubitStateVector)):
uses_stateprep = True
continue
elif isinstance(o, Rot):
op_list = o.expand().operations
else:
op_list = [o]

for single_op in op_list:
is_inverse = single_op.inverse

name = single_op.name if not is_inverse else single_op.name[:-4]
names.append(name)

if getattr(StateVectorC128, name, None) is None:
params.append([])
mats.append(single_op.matrix)

if is_inverse:
is_inverse = False
else:
params.append(single_op.parameters)
mats.append([])

wires_list = single_op.wires.tolist()
wires.append([wires_map[w] for w in wires_list])
inverses.append(is_inverse)
return (names, params, wires, inverses, mats), uses_stateprep
Loading