Skip to content

Commit 4659093

Browse files
rauletorrescringo-but-quantummlxdpaul0403maliasadi
authored
Downstream LightningSimulator C++ API to the pennylane-lightning repository (#960)
**Context:** Catalyst needs to build a class wrapping the Lightning Qubit class. Here we are moving the logic from Catalyst to the Lightning repository. **Description of the Change:** Moving code from Catalyst to this repository and updating the build system to build against Catalyst. **Benefits:** Catalyst wheels will build faster. **Possible Drawbacks:** Our build system now relies on headers coming from Catalyst. It is unclear if this may cause a deadlock in the future because of our cyclic dependencies (PennyLane, PennyLane Lightning, Catalyst). Chances are small because we don't rely on Catalyst wheels or build it from scratch. [sc-70316] [sc-70318] [sc-70317] --------- Co-authored-by: ringo-but-quantum <[email protected]> Co-authored-by: Lee James O'Riordan <[email protected]> Co-authored-by: paul0403 <[email protected]> Co-authored-by: Haochen Wang <[email protected]> Co-authored-by: Ali Asadi <[email protected]>
1 parent b491a37 commit 4659093

22 files changed

+5062
-8
lines changed

.github/CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
* Add native N-controlled generators and adjoint support to `lightning.gpu`'s single-GPU backend.
66
[(#970)](https://github.com/PennyLaneAI/pennylane-lightning/pull/970)
77

8+
* Add a Catalyst-specific wrapping class for Lightning Qubit.
9+
[(#960)](https://github.com/PennyLaneAI/pennylane-lightning/pull/960)
10+
811
* Add native N-controlled gates support to `lightning.gpu`'s single-GPU backend.
912
[(#938)](https://github.com/PennyLaneAI/pennylane-lightning/pull/938)
1013

@@ -35,7 +38,7 @@
3538

3639
This release contains contributions from (in alphabetical order):
3740

38-
Ali Asadi, Joseph Lee, Luis Alfredo Nuñez Meneses, Shuli Shu
41+
Ali Asadi, Joseph Lee, Luis Alfredo Nuñez Meneses, Shuli Shu, Raul Torres, Haochen Paul Wang
3942

4043
---
4144

.github/workflows/tests_lqcpu_python.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,11 @@ jobs:
197197
- name: Run PennyLane-Lightning unit tests
198198
run: |
199199
DEVICENAME=`echo ${{ matrix.pl_backend }} | sed "s/_/./g"`
200-
OMP_NUM_THREADS=1 PL_DEVICE=${DEVICENAME} python -m pytest -n auto tests/ -k "not unitary_correct" \
200+
# Remove `python -m` to avoid running tests with relative modules
201+
OMP_NUM_THREADS=1 PL_DEVICE=${DEVICENAME} pytest -n auto tests/ -k "not unitary_correct" \
201202
$COVERAGE_FLAGS --splits 4 --group ${{ matrix.group }} \
202203
--durations-path='.github/workflows/python_lightning_qubit_test_durations.json' --splitting-algorithm=least_duration
203-
PL_DEVICE=${DEVICENAME} python -m pytest tests/ -k "unitary_correct" $COVERAGE_FLAGS --cov-append
204+
PL_DEVICE=${DEVICENAME} pytest tests/ -k "unitary_correct" $COVERAGE_FLAGS --cov-append
204205
pl-device-test --device ${DEVICENAME} --skip-ops --shots=20000 $COVERAGE_FLAGS --cov-append
205206
pl-device-test --device ${DEVICENAME} --shots=None --skip-ops $COVERAGE_FLAGS --cov-append
206207
mv .coverage ${{ github.workspace }}/.coverage-${{ github.job }}-${{ matrix.pl_backend }}-${{ matrix.blas }}-${{ matrix.group }}

cmake/support_catalyst.cmake

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ macro(FindCatalyst target_name)
4242
${HEADER_NAME}
4343
URL https://raw.githubusercontent.com/PennyLaneAI/catalyst/${CATALYST_GIT_TAG}/runtime/lib/backend/common/${HEADER}
4444
DOWNLOAD_NO_EXTRACT True
45-
SOURCE_DIR include
45+
SOURCE_DIR ../../include
4646
)
4747

4848
FetchContent_MakeAvailable(${HEADER_NAME})
@@ -62,13 +62,13 @@ macro(FindCatalyst target_name)
6262
${HEADER_NAME}
6363
URL https://raw.githubusercontent.com/PennyLaneAI/catalyst/${CATALYST_GIT_TAG}/runtime/include/${HEADER}
6464
DOWNLOAD_NO_EXTRACT True
65-
SOURCE_DIR include
65+
SOURCE_DIR ../../include
6666
)
6767

6868
FetchContent_MakeAvailable(${HEADER_NAME})
6969
endforeach()
7070

71-
target_include_directories(${target_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include)
71+
target_include_directories(${target_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/../../include)
7272

7373
endif()
7474
endmacro()

pennylane_lightning/core/_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.40.0-dev6"
19+
__version__ = "0.40.0-dev7"

pennylane_lightning/core/src/simulators/lightning_qubit/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ set(COMPONENT_SUBDIRS algorithms
8989
utils
9090
)
9191

92+
# Do not build the LQ plugin for Windows
93+
if (NOT WIN32)
94+
set(COMPONENT_SUBDIRS ${COMPONENT_SUBDIRS}
95+
catalyst
96+
)
97+
endif()
98+
9299
foreach(COMP ${COMPONENT_SUBDIRS})
93100
add_subdirectory(${COMP})
94101
endforeach()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
project(lightning_qubit_catalyst LANGUAGES CXX)
4+
5+
set(LQ_CATALYST_FILES LightningSimulator.cpp CACHE INTERNAL "")
6+
add_library(lightning_qubit_catalyst SHARED ${LQ_CATALYST_FILES})
7+
8+
include(FetchContent)
9+
10+
include("${pennylane_lightning_SOURCE_DIR}/cmake/support_catalyst.cmake")
11+
FindCatalyst(lightning_qubit_catalyst)
12+
13+
target_include_directories(lightning_qubit_catalyst INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
14+
target_link_libraries(lightning_qubit_catalyst PUBLIC lightning_compile_options
15+
lightning_external_libs
16+
lightning_qubit_algorithms
17+
lightning_qubit_measurements
18+
lightning_qubit_observables
19+
)
20+
21+
if (BUILD_TESTS)
22+
enable_testing()
23+
add_subdirectory("tests")
24+
endif()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// Copyright 2022 Xanadu Quantum Technologies Inc.
2+
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
#include <array>
18+
#include <stdexcept>
19+
#include <tuple>
20+
#include <utility>
21+
22+
#include "Exception.hpp"
23+
#include "Types.h"
24+
#include "Utils.hpp"
25+
26+
#include "ObservablesLQubit.hpp"
27+
#include "StateVectorLQubitDynamic.hpp"
28+
29+
namespace {
30+
using Pennylane::LightningQubit::StateVectorLQubitDynamic;
31+
using Pennylane::LightningQubit::Observables::HermitianObs;
32+
using Pennylane::LightningQubit::Observables::NamedObs;
33+
using Pennylane::LightningQubit::Observables::TensorProdObs;
34+
using Pennylane::Observables::Observable;
35+
} // namespace
36+
37+
namespace Catalyst::Runtime::Simulator {
38+
39+
/**
40+
* @brief The LightningObsManager caches observables of a program at runtime
41+
* and maps each one to a const unique index (`int64_t`) in the scope
42+
* of the global context manager.
43+
*/
44+
template <typename PrecisionT> class LightningObsManager {
45+
private:
46+
using VectorStateT = StateVectorLQubitDynamic<PrecisionT>;
47+
using ComplexT = typename VectorStateT::ComplexT;
48+
using ObservablePairType =
49+
std::pair<std::shared_ptr<Observable<VectorStateT>>, ObsType>;
50+
std::vector<ObservablePairType> observables_{};
51+
52+
public:
53+
LightningObsManager() = default;
54+
~LightningObsManager() = default;
55+
56+
LightningObsManager(const LightningObsManager &) = delete;
57+
LightningObsManager &operator=(const LightningObsManager &) = delete;
58+
LightningObsManager(LightningObsManager &&) = delete;
59+
LightningObsManager &operator=(LightningObsManager &&) = delete;
60+
61+
/**
62+
* @brief A helper function to clear constructed observables in the program.
63+
*/
64+
void clear() { observables_.clear(); }
65+
66+
/**
67+
* @brief Check the validity of observable keys.
68+
*
69+
* @param obsKeys The vector of observable keys
70+
* @return bool
71+
*/
72+
[[nodiscard]] auto
73+
isValidObservables(const std::vector<ObsIdType> &obsKeys) const -> bool {
74+
return std::all_of(obsKeys.begin(), obsKeys.end(), [this](auto i) {
75+
return (i >= 0 && static_cast<size_t>(i) < observables_.size());
76+
});
77+
}
78+
79+
/**
80+
* @brief Get the constructed observable instance.
81+
*
82+
* @param key The observable key
83+
* @return std::shared_ptr<Observable<VectorStateT>>
84+
*/
85+
[[nodiscard]] auto getObservable(ObsIdType key)
86+
-> std::shared_ptr<Observable<VectorStateT>> {
87+
RT_FAIL_IF(!isValidObservables({key}), "Invalid observable key");
88+
return std::get<0>(observables_[key]);
89+
}
90+
91+
/**
92+
* @brief Get the number of observables.
93+
*
94+
* @return size_t
95+
*/
96+
[[nodiscard]] auto numObservables() const -> size_t {
97+
return observables_.size();
98+
}
99+
100+
/**
101+
* @brief Create and cache a new NamedObs instance.
102+
*
103+
* @param obsId The named observable id of type ObsId
104+
* @param wires The vector of wires the observable acts on
105+
* @return ObsIdType
106+
*/
107+
[[nodiscard]] auto createNamedObs(ObsId obsId,
108+
const std::vector<size_t> &wires)
109+
-> ObsIdType {
110+
auto &&obs_str = std::string(
111+
Lightning::lookup_obs<Lightning::simulator_observable_support_size>(
112+
Lightning::simulator_observable_support, obsId));
113+
114+
observables_.push_back(std::make_pair(
115+
std::make_shared<NamedObs<VectorStateT>>(obs_str, wires),
116+
ObsType::Basic));
117+
return static_cast<ObsIdType>(observables_.size() - 1);
118+
}
119+
120+
/**
121+
* @brief Create and cache a new HermitianObs instance.
122+
*
123+
* @param matrix The row-wise Hermitian matrix
124+
* @param wires The vector of wires the observable acts on
125+
* @return ObsIdType
126+
*/
127+
[[nodiscard]] auto createHermitianObs(const std::vector<ComplexT> &matrix,
128+
const std::vector<size_t> &wires)
129+
-> ObsIdType {
130+
observables_.push_back(
131+
std::make_pair(std::make_shared<HermitianObs<VectorStateT>>(
132+
HermitianObs<VectorStateT>{matrix, wires}),
133+
ObsType::Basic));
134+
135+
return static_cast<ObsIdType>(observables_.size() - 1);
136+
}
137+
138+
/**
139+
* @brief Create and cache a new TensorProd instance.
140+
*
141+
* @param obsKeys The vector of observable keys
142+
* @return ObsIdType
143+
*/
144+
[[nodiscard]] auto
145+
createTensorProdObs(const std::vector<ObsIdType> &obsKeys) -> ObsIdType {
146+
const auto key_size = obsKeys.size();
147+
const auto obs_size = observables_.size();
148+
149+
std::vector<std::shared_ptr<Observable<VectorStateT>>> obs_vec;
150+
obs_vec.reserve(key_size);
151+
152+
for (const auto &key : obsKeys) {
153+
RT_FAIL_IF(static_cast<size_t>(key) >= obs_size || key < 0,
154+
"Invalid observable key");
155+
156+
auto &&[obs, type] = observables_[key];
157+
obs_vec.push_back(obs);
158+
}
159+
160+
observables_.push_back(std::make_pair(
161+
TensorProdObs<VectorStateT>::create(obs_vec), ObsType::TensorProd));
162+
163+
return static_cast<ObsIdType>(obs_size);
164+
}
165+
166+
/**
167+
* @brief Create and cache a new HamiltonianObs instance.
168+
*
169+
* @param coeffs The vector of coefficients
170+
* @param obsKeys The vector of observable keys
171+
* @return ObsIdType
172+
*/
173+
[[nodiscard]] auto
174+
createHamiltonianObs(const std::vector<PrecisionT> &coeffs,
175+
const std::vector<ObsIdType> &obsKeys) -> ObsIdType {
176+
const auto key_size = obsKeys.size();
177+
const auto obs_size = observables_.size();
178+
179+
RT_FAIL_IF(
180+
key_size != coeffs.size(),
181+
"Incompatible list of observables and coefficients; "
182+
"Number of observables and number of coefficients must be equal");
183+
184+
std::vector<std::shared_ptr<Observable<VectorStateT>>> obs_vec;
185+
obs_vec.reserve(key_size);
186+
187+
for (auto key : obsKeys) {
188+
RT_FAIL_IF(static_cast<size_t>(key) >= obs_size || key < 0,
189+
"Invalid observable key");
190+
191+
auto &&[obs, type] = observables_[key];
192+
obs_vec.push_back(obs);
193+
}
194+
195+
observables_.push_back(std::make_pair(
196+
std::make_shared<Pennylane::LightningQubit::Observables::
197+
Hamiltonian<VectorStateT>>(
198+
Pennylane::LightningQubit::Observables::Hamiltonian<
199+
VectorStateT>(coeffs, std::move(obs_vec))),
200+
ObsType::Hamiltonian));
201+
202+
return static_cast<ObsIdType>(obs_size);
203+
}
204+
};
205+
} // namespace Catalyst::Runtime::Simulator

0 commit comments

Comments
 (0)