pennylane-qrack 0.8.1__tar.gz → 0.8.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pennylane-qrack might be problematic. Click here for more details.

Files changed (30) hide show
  1. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/Makefile +1 -1
  2. {pennylane_qrack-0.8.1/pennylane_qrack.egg-info → pennylane_qrack-0.8.4}/PKG-INFO +1 -1
  3. pennylane_qrack-0.8.4/catalyst/runtime/include/DataView.hpp +147 -0
  4. pennylane_qrack-0.8.4/catalyst/runtime/include/Exception.hpp +87 -0
  5. pennylane_qrack-0.8.4/catalyst/runtime/include/QuantumDevice.hpp +319 -0
  6. pennylane_qrack-0.8.4/catalyst/runtime/include/RuntimeCAPI.h +109 -0
  7. pennylane_qrack-0.8.4/catalyst/runtime/include/Types.h +156 -0
  8. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack/QrackDeviceConfig.toml +3 -7
  9. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack/_version.py +1 -1
  10. pennylane_qrack-0.8.4/pennylane_qrack/libqrack_device.so +0 -0
  11. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack/qrack_device.cpp +17 -83
  12. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4/pennylane_qrack.egg-info}/PKG-INFO +1 -1
  13. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack.egg-info/SOURCES.txt +6 -0
  14. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/CHANGELOG.md +0 -0
  15. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/CMakeLists.txt +0 -0
  16. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/LICENSE +0 -0
  17. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/MANIFEST.in +0 -0
  18. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/README.rst +0 -0
  19. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack/__init__.py +0 -0
  20. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack/qrack_device.py +0 -0
  21. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack.egg-info/dependency_links.txt +0 -0
  22. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack.egg-info/entry_points.txt +0 -0
  23. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack.egg-info/requires.txt +0 -0
  24. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/pennylane_qrack.egg-info/top_level.txt +0 -0
  25. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/requirements.txt +0 -0
  26. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/setup.cfg +0 -0
  27. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/setup.py +0 -0
  28. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/tests/test_apply.py +0 -0
  29. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/tests/test_integration.py +0 -0
  30. {pennylane_qrack-0.8.1 → pennylane_qrack-0.8.4}/tests/test_units.py +0 -0
@@ -24,7 +24,7 @@ help:
24
24
  build-deps:
25
25
  ifneq ($(OS),Windows_NT)
26
26
  ifeq ($(QRACK_PRESENT),)
27
- git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout a73d1e66272ab24cdee1e4a386702951474b4e69; cd ..
27
+ git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout 99de260f9df4f91565fb3ffc2f2bacd7385e09f2; cd ..
28
28
  endif
29
29
  mkdir -p qrack/build
30
30
  ifeq ($(UNAME_S),Linux)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pennylane-qrack
3
- Version: 0.8.1
3
+ Version: 0.8.4
4
4
  Summary: PennyLane plugin for Qrack.
5
5
  Home-page: http://github.com/vm6502q
6
6
  Maintainer: vm6502q
@@ -0,0 +1,147 @@
1
+ // Copyright 2023 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 <Exception.hpp>
18
+
19
+ /**
20
+ * A multi-dimensional view for MemRef-like and std::vector<T> types.
21
+ *
22
+ * @tparam T The underlying data type
23
+ * @tparam R The Rank (R > 0)
24
+ *
25
+ * @note A forward iterator is implemented in this view for traversing over the entire
26
+ * elements of MemRef types rank-by-rank starting from the last dimension (R-1). For example,
27
+ * The DataView iterator for MemRef<T, 2> starts from index (0, 0) and traverses elements
28
+ * in the following order:
29
+ * (0, 0), ..., (0, sizes[1]-1), (1, 0), ..., (1, sizes[1]-1), ... (sizes[0]-1, sizes[1]-1).
30
+ */
31
+ template <typename T, size_t R> class DataView {
32
+ private:
33
+ T *data_aligned;
34
+ size_t offset;
35
+ size_t sizes[R] = {0};
36
+ size_t strides[R] = {0};
37
+
38
+ public:
39
+ class iterator {
40
+ private:
41
+ const DataView<T, R> &view;
42
+
43
+ int64_t loc; // physical index
44
+ size_t indices[R] = {0};
45
+
46
+ public:
47
+ using iterator_category = std::forward_iterator_tag; // LCOV_EXCL_LINE
48
+ using value_type = T; // LCOV_EXCL_LINE
49
+ using difference_type = std::ptrdiff_t; // LCOV_EXCL_LINE
50
+ using pointer = T *; // LCOV_EXCL_LINE
51
+ using reference = T &; // LCOV_EXCL_LINE
52
+
53
+ iterator(const DataView<T, R> &_view, int64_t begin_idx) : view(_view), loc(begin_idx) {}
54
+ pointer operator->() const { return &view.data_aligned[loc]; }
55
+ reference operator*() const { return view.data_aligned[loc]; }
56
+ iterator &operator++()
57
+ {
58
+ int64_t next_axis = -1;
59
+ int64_t idx;
60
+ for (int64_t i = R; i > 0; --i) {
61
+ idx = i - 1;
62
+ if (indices[idx]++ < view.sizes[idx] - 1) {
63
+ next_axis = idx;
64
+ break;
65
+ }
66
+ indices[idx] = 0;
67
+ loc -= (view.sizes[idx] - 1) * view.strides[idx];
68
+ }
69
+
70
+ loc = next_axis == -1 ? -1 : loc + view.strides[next_axis];
71
+ return *this;
72
+ }
73
+ iterator operator++(int)
74
+ {
75
+ auto tmp = *this;
76
+ int64_t next_axis = -1;
77
+ int64_t idx;
78
+ for (int64_t i = R; i > 0; --i) {
79
+ idx = i - 1;
80
+ if (indices[idx]++ < view.sizes[idx] - 1) {
81
+ next_axis = idx;
82
+ break;
83
+ }
84
+ indices[idx] = 0;
85
+ loc -= (view.sizes[idx] - 1) * view.strides[idx];
86
+ }
87
+
88
+ loc = next_axis == -1 ? -1 : loc + view.strides[next_axis];
89
+ return tmp;
90
+ }
91
+ bool operator==(const iterator &other) const
92
+ {
93
+ return (loc == other.loc && view.data_aligned == other.view.data_aligned);
94
+ }
95
+ bool operator!=(const iterator &other) const { return !(*this == other); }
96
+ };
97
+
98
+ explicit DataView(std::vector<T> &buffer) : data_aligned(buffer.data()), offset(0)
99
+ {
100
+ static_assert(R == 1, "[Class: DataView] Assertion: R == 1");
101
+ sizes[0] = buffer.size();
102
+ strides[0] = 1;
103
+ }
104
+
105
+ explicit DataView(T *_data_aligned, size_t _offset, size_t *_sizes, size_t *_strides)
106
+ : data_aligned(_data_aligned), offset(_offset)
107
+ {
108
+ static_assert(R > 0, "[Class: DataView] Assertion: R > 0");
109
+ if (_sizes && _strides) {
110
+ for (size_t i = 0; i < R; i++) {
111
+ sizes[i] = _sizes[i];
112
+ strides[i] = _strides[i];
113
+ }
114
+ } // else sizes = {0}, strides = {0}
115
+ }
116
+
117
+ [[nodiscard]] auto size() const -> size_t
118
+ {
119
+ if (!data_aligned) {
120
+ return 0;
121
+ }
122
+
123
+ size_t tsize = 1;
124
+ for (size_t i = 0; i < R; i++) {
125
+ tsize *= sizes[i];
126
+ }
127
+ return tsize;
128
+ }
129
+
130
+ template <typename... I> T &operator()(I... idxs) const
131
+ {
132
+ static_assert(sizeof...(idxs) == R,
133
+ "[Class: DataView] Error in Catalyst Runtime: Wrong number of indices");
134
+ size_t indices[] = {static_cast<size_t>(idxs)...};
135
+
136
+ size_t loc = offset;
137
+ for (size_t axis = 0; axis < R; axis++) {
138
+ RT_ASSERT(indices[axis] < sizes[axis]);
139
+ loc += indices[axis] * strides[axis];
140
+ }
141
+ return data_aligned[loc];
142
+ }
143
+
144
+ iterator begin() { return iterator{*this, static_cast<int64_t>(offset)}; }
145
+
146
+ iterator end() { return iterator{*this, -1}; }
147
+ };
@@ -0,0 +1,87 @@
1
+ // Copyright 2023 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 <exception>
18
+ #include <iostream>
19
+
20
+ #include <sstream>
21
+ #include <string>
22
+ #include <type_traits>
23
+ #include <utility>
24
+
25
+ /**
26
+ * @brief Macro that throws `RuntimeException` with given message.
27
+ */
28
+ #define RT_FAIL(message) Catalyst::Runtime::_abort((message), __FILE__, __LINE__, __func__)
29
+
30
+ /**
31
+ * @brief Macro that throws `RuntimeException` if expression evaluates
32
+ * to true.
33
+ */
34
+ #define RT_FAIL_IF(expression, message) \
35
+ if ((expression)) { \
36
+ RT_FAIL(message); \
37
+ }
38
+
39
+ /**
40
+ * @brief Macro that throws `RuntimeException` with the given expression
41
+ * and source location if expression evaluates to false.
42
+ */
43
+ #define RT_ASSERT(expression) RT_FAIL_IF(!(expression), "Assertion: " #expression)
44
+
45
+ namespace Catalyst::Runtime {
46
+
47
+ /**
48
+ * @brief This is the general exception thrown by Catalyst for runtime errors
49
+ * that is derived from `std::exception`.
50
+ */
51
+ class RuntimeException : public std::exception {
52
+ private:
53
+ const std::string err_msg;
54
+
55
+ public:
56
+ explicit RuntimeException(std::string msg) noexcept
57
+ : err_msg{std::move(msg)} {} // LCOV_EXCL_LINE
58
+ ~RuntimeException() override = default; // LCOV_EXCL_LINE
59
+
60
+ RuntimeException(const RuntimeException &) = default;
61
+ RuntimeException(RuntimeException &&) noexcept = default;
62
+
63
+ RuntimeException &operator=(const RuntimeException &) = delete;
64
+ RuntimeException &operator=(RuntimeException &&) = delete;
65
+
66
+ [[nodiscard]] auto what() const noexcept -> const char * override
67
+ {
68
+ return err_msg.c_str();
69
+ } // LCOV_EXCL_LINE
70
+ };
71
+
72
+ /**
73
+ * @brief Throws a `RuntimeException` with the given error message.
74
+ *
75
+ * @note This is not supposed to be called directly.
76
+ */
77
+ [[noreturn]] inline void _abort(const char *message, const char *file_name, size_t line,
78
+ const char *function_name)
79
+ {
80
+ std::stringstream sstream;
81
+ sstream << "[" << file_name << "][Line:" << line << "][Function:" << function_name
82
+ << "] Error in Catalyst Runtime: " << message;
83
+
84
+ throw RuntimeException(sstream.str());
85
+ } // LCOV_EXCL_LINE
86
+
87
+ } // namespace Catalyst::Runtime
@@ -0,0 +1,319 @@
1
+ // Copyright 2022-2023 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 <complex>
18
+ #include <memory>
19
+ #include <optional>
20
+ #include <vector>
21
+
22
+ #include "DataView.hpp"
23
+ #include "Types.h"
24
+
25
+ // A helper template macro to generate the <IDENTIFIER>Factory method by
26
+ // calling <CONSTRUCTOR>(kwargs). Check the Custom Devices guideline for details:
27
+ // https://docs.pennylane.ai/projects/catalyst/en/stable/dev/custom_devices.html
28
+ #define GENERATE_DEVICE_FACTORY(IDENTIFIER, CONSTRUCTOR) \
29
+ extern "C" Catalyst::Runtime::QuantumDevice *IDENTIFIER##Factory(const char *kwargs) \
30
+ { \
31
+ return new CONSTRUCTOR(std::string(kwargs)); \
32
+ }
33
+
34
+ namespace Catalyst::Runtime {
35
+
36
+ /**
37
+ * @brief struct API for backend quantum devices.
38
+ *
39
+ * This device API contains,
40
+ * - a set of methods to manage qubit allocations and deallocations, device shot
41
+ * noise, and quantum tape recording as well as reference values for the result
42
+ * data-type; these are used to implement Quantum Runtime (QR) instructions.
43
+ *
44
+ * - a set of methods for quantum operations, observables, measurements, and gradient
45
+ * of the device; these are used to implement Quantum Instruction Set (QIS) instructions.
46
+ *
47
+ */
48
+ struct QuantumDevice {
49
+ QuantumDevice() = default; // LCOV_EXCL_LINE
50
+ virtual ~QuantumDevice() = default; // LCOV_EXCL_LINE
51
+
52
+ QuantumDevice &operator=(const QuantumDevice &) = delete;
53
+ QuantumDevice(const QuantumDevice &) = delete;
54
+ QuantumDevice(QuantumDevice &&) = delete;
55
+ QuantumDevice &operator=(QuantumDevice &&) = delete;
56
+
57
+ /**
58
+ * @brief Allocate a qubit.
59
+ *
60
+ * @return `QubitIdType`
61
+ */
62
+ virtual auto AllocateQubit() -> QubitIdType = 0;
63
+
64
+ /**
65
+ * @brief Allocate a vector of qubits.
66
+ *
67
+ * @param num_qubits The number of qubits to allocate.
68
+ *
69
+ * @return `std::vector<QubitIdType>`
70
+ */
71
+ virtual auto AllocateQubits(size_t num_qubits) -> std::vector<QubitIdType> = 0;
72
+
73
+ /**
74
+ * @brief Release a qubit.
75
+ *
76
+ * @param qubit The id of the qubit
77
+ */
78
+ virtual void ReleaseQubit(QubitIdType qubit) = 0;
79
+
80
+ /**
81
+ * @brief Release all qubits.
82
+ */
83
+ virtual void ReleaseAllQubits() = 0;
84
+
85
+ /**
86
+ * @brief Get the number of allocated qubits.
87
+ *
88
+ * @return `size_t`
89
+ */
90
+ [[nodiscard]] virtual auto GetNumQubits() const -> size_t = 0;
91
+
92
+ /**
93
+ * @brief Set the number of device shots.
94
+ *
95
+ * @param shots The number of noise shots
96
+ */
97
+ virtual void SetDeviceShots(size_t shots) = 0;
98
+
99
+ /**
100
+ * @brief Get the number of device shots.
101
+ *
102
+ * @return `size_t`
103
+ */
104
+ [[nodiscard]] virtual auto GetDeviceShots() const -> size_t = 0;
105
+
106
+ /**
107
+ * @brief Start recording a quantum tape if provided.
108
+ *
109
+ * @note This is backed by the `Catalyst::Runtime::CacheManager<ComplexT>` property in
110
+ * the device implementation.
111
+ */
112
+ virtual void StartTapeRecording() = 0;
113
+
114
+ /**
115
+ * @brief Stop recording a quantum tape if provided.
116
+ *
117
+ * @note This is backed by the `Catalyst::Runtime::CacheManager<ComplexT>` property in
118
+ * the device implementation.
119
+ */
120
+ virtual void StopTapeRecording() = 0;
121
+
122
+ /**
123
+ * @brief Result value for "Zero" used in the measurement process.
124
+ *
125
+ * @return `Result`
126
+ */
127
+ [[nodiscard]] virtual auto Zero() const -> Result = 0;
128
+
129
+ /**
130
+ * @brief Result value for "One" used in the measurement process.
131
+ *
132
+ * @return `Result`
133
+ */
134
+ [[nodiscard]] virtual auto One() const -> Result = 0;
135
+
136
+ /**
137
+ * @brief A helper method to print the state vector of a device.
138
+ */
139
+ virtual void PrintState() = 0;
140
+
141
+ /**
142
+ * @brief Apply a single gate to the state vector of a device with its name if this is
143
+ * supported.
144
+ *
145
+ * @param name The name of the gate to apply
146
+ * @param params Optional parameter list for parametric gates
147
+ * @param wires Wires to apply gate to
148
+ * @param inverse Indicates whether to use inverse of gate
149
+ * @param controlled_wires Optional controlled wires applied to the operation
150
+ * @param controlled_values Optional controlled values applied to the operation
151
+ */
152
+ virtual void
153
+ NamedOperation(const std::string &name, const std::vector<double> &params,
154
+ const std::vector<QubitIdType> &wires, [[maybe_unused]] bool inverse = false,
155
+ [[maybe_unused]] const std::vector<QubitIdType> &controlled_wires = {},
156
+ [[maybe_unused]] const std::vector<bool> &controlled_values = {}) = 0;
157
+
158
+ /**
159
+ * @brief Apply a given matrix directly to the state vector of a device.
160
+ *
161
+ * @param matrix The matrix of data in row-major format
162
+ * @param wires Wires to apply gate to
163
+ * @param inverse Indicates whether to use inverse of gate
164
+ * @param controlled_wires Controlled wires applied to the operation
165
+ * @param controlled_values Controlled values applied to the operation
166
+ */
167
+ virtual void
168
+ MatrixOperation(const std::vector<std::complex<double>> &matrix,
169
+ const std::vector<QubitIdType> &wires, [[maybe_unused]] bool inverse = false,
170
+ [[maybe_unused]] const std::vector<QubitIdType> &controlled_wires = {},
171
+ [[maybe_unused]] const std::vector<bool> &controlled_values = {}) = 0;
172
+
173
+ /**
174
+ * @brief Construct a named (Identity, PauliX, PauliY, PauliZ, and Hadamard)
175
+ * or Hermitian observable.
176
+ *
177
+ * @param id The type of the observable
178
+ * @param matrix The matrix of data to construct a hermitian observable
179
+ * @param wires Wires to apply observable to
180
+ *
181
+ * @return `ObsIdType` Index of the constructed observable
182
+ */
183
+ virtual auto Observable(ObsId id, const std::vector<std::complex<double>> &matrix,
184
+ const std::vector<QubitIdType> &wires) -> ObsIdType = 0;
185
+
186
+ /**
187
+ * @brief Construct a tensor product of observables.
188
+ *
189
+ * @param obs The vector of observables indices of type ObsIdType
190
+ *
191
+ * @return `ObsIdType` Index of the constructed observable
192
+ */
193
+ virtual auto TensorObservable(const std::vector<ObsIdType> &obs) -> ObsIdType = 0;
194
+
195
+ /**
196
+ * @brief Construct a Hamiltonian observable.
197
+ *
198
+ * @param coeffs The vector of coefficients
199
+ * @param obs The vector of observables indices of size `coeffs`
200
+ *
201
+ * @return `ObsIdType` Index of the constructed observable
202
+ */
203
+ virtual auto HamiltonianObservable(const std::vector<double> &coeffs,
204
+ const std::vector<ObsIdType> &obs) -> ObsIdType = 0;
205
+
206
+ /**
207
+ * @brief Compute the expected value of an observable.
208
+ *
209
+ * @param obsKey The index of the constructed observable
210
+ *
211
+ * @return `double` The expected value
212
+ */
213
+ virtual auto Expval(ObsIdType obsKey) -> double = 0;
214
+
215
+ /**
216
+ * @brief Compute the variance of an observable.
217
+ *
218
+ * @param obsKey The index of the constructed observable
219
+ *
220
+ * @return `double` The variance
221
+ */
222
+ virtual auto Var(ObsIdType obsKey) -> double = 0;
223
+
224
+ /**
225
+ * @brief Get the state-vector of a device.
226
+ *
227
+ * @param state The pre-allocated `DataView<complex<double>, 1>`
228
+ */
229
+ virtual void State(DataView<std::complex<double>, 1> &state) = 0;
230
+
231
+ /**
232
+ * @brief Compute the probabilities of each computational basis state.
233
+
234
+ * @param probs The pre-allocated `DataView<double, 1>`
235
+ */
236
+ virtual void Probs(DataView<double, 1> &probs) = 0;
237
+
238
+ /**
239
+ * @brief Compute the probabilities for a subset of the full system.
240
+ *
241
+ * @param probs The pre-allocated `DataView<double, 1>`
242
+ * @param wires Wires will restrict probabilities to a subset of the full system
243
+ */
244
+ virtual void PartialProbs(DataView<double, 1> &probs,
245
+ const std::vector<QubitIdType> &wires) = 0;
246
+
247
+ /**
248
+ * @brief Compute samples with the number of shots on the entire wires,
249
+ * returing raw samples.
250
+ *
251
+ * @param samples The pre-allocated `DataView<double, 2>`representing a matrix of
252
+ * shape `shots * numQubits`. The built-in iterator in `DataView<double, 2>`
253
+ * iterates over all elements of `samples` row-wise.
254
+ * @param shots The number of shots
255
+ */
256
+ virtual void Sample(DataView<double, 2> &samples, size_t shots) = 0;
257
+
258
+ /**
259
+ * @brief Compute partial samples with the number of shots on `wires`,
260
+ * returing raw samples.
261
+ *
262
+ * @param samples The pre-allocated `DataView<double, 2>`representing a matrix of
263
+ * shape `shots * numWires`. The built-in iterator in `DataView<double, 2>`
264
+ * iterates over all elements of `samples` row-wise.
265
+ * @param wires Wires to compute samples on
266
+ * @param shots The number of shots
267
+ */
268
+ virtual void PartialSample(DataView<double, 2> &samples, const std::vector<QubitIdType> &wires,
269
+ size_t shots) = 0;
270
+
271
+ /**
272
+ * @brief Sample with the number of shots on the entire wires, returning the
273
+ * number of counts for each sample.
274
+ *
275
+ * @param eigvals The pre-allocated `DataView<double, 1>`
276
+ * @param counts The pre-allocated `DataView<int64_t, 1>`
277
+ * @param shots The number of shots
278
+ */
279
+ virtual void Counts(DataView<double, 1> &eigvals, DataView<int64_t, 1> &counts,
280
+ size_t shots) = 0;
281
+
282
+ /**
283
+ * @brief Partial sample with the number of shots on `wires`, returning the
284
+ * number of counts for each sample.
285
+ *
286
+ * @param eigvals The pre-allocated `DataView<double, 1>`
287
+ * @param counts The pre-allocated `DataView<int64_t, 1>`
288
+ * @param wires Wires to compute samples on
289
+ * @param shots The number of shots
290
+ */
291
+ virtual void PartialCounts(DataView<double, 1> &eigvals, DataView<int64_t, 1> &counts,
292
+ const std::vector<QubitIdType> &wires, size_t shots) = 0;
293
+
294
+ /**
295
+ * @brief A general measurement method that acts on a single wire.
296
+ *
297
+ * @param wire The wire to compute Measure on
298
+ * @param postselect Which basis state to postselect after a mid-circuit measurement (-1 denotes
299
+ no post-selection)
300
+
301
+ * @return `Result` The measurement result
302
+ */
303
+ virtual auto Measure(QubitIdType wire, std::optional<int32_t> postselect) -> Result = 0;
304
+
305
+ /**
306
+ * @brief Compute the gradient of a quantum tape, that is cached using
307
+ * `Catalyst::Runtime::Simulator::CacheManager`, for a specific set of trainable
308
+ * parameters.
309
+ *
310
+ * @param gradients The vector of pre-allocated `DataView<double, 1>*`
311
+ * to store gradients resutls for the list of cached observables.
312
+ * @param trainParams The vector of trainable parameters; if none, all parameters
313
+ * would be assumed trainable
314
+ *
315
+ */
316
+ virtual void Gradient(std::vector<DataView<double, 1>> &gradients,
317
+ const std::vector<size_t> &trainParams) = 0;
318
+ };
319
+ } // namespace Catalyst::Runtime
@@ -0,0 +1,109 @@
1
+ // Copyright 2022-2023 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
+ #ifndef RUNTIMECAPI_H
17
+ #define RUNTIMECAPI_H
18
+
19
+ #include "Types.h"
20
+
21
+ #ifdef __cplusplus
22
+ extern "C" {
23
+ #endif
24
+
25
+ // Quantum Runtime Instructions
26
+ void __catalyst__rt__fail_cstr(const char *);
27
+ void __catalyst__rt__initialize();
28
+ void __catalyst__rt__device_init(int8_t *, int8_t *, int8_t *);
29
+ void __catalyst__rt__device_release();
30
+ void __catalyst__rt__finalize();
31
+ void __catalyst__rt__toggle_recorder(bool);
32
+ void __catalyst__rt__print_state();
33
+ void __catalyst__rt__print_tensor(OpaqueMemRefT *, bool);
34
+ void __catalyst__rt__print_string(char *);
35
+ int64_t __catalyst__rt__array_get_size_1d(QirArray *);
36
+ int8_t *__catalyst__rt__array_get_element_ptr_1d(QirArray *, int64_t);
37
+
38
+ QUBIT *__catalyst__rt__qubit_allocate();
39
+ QirArray *__catalyst__rt__qubit_allocate_array(int64_t);
40
+ void __catalyst__rt__qubit_release(QUBIT *);
41
+ void __catalyst__rt__qubit_release_array(QirArray *);
42
+
43
+ int64_t __catalyst__rt__num_qubits();
44
+
45
+ bool __catalyst__rt__result_equal(RESULT *, RESULT *);
46
+ RESULT *__catalyst__rt__result_get_one();
47
+ RESULT *__catalyst__rt__result_get_zero();
48
+
49
+ // Quantum Gate Set Instructions
50
+ void __catalyst__qis__Identity(QUBIT *, const Modifiers *);
51
+ void __catalyst__qis__PauliX(QUBIT *, const Modifiers *);
52
+ void __catalyst__qis__PauliY(QUBIT *, const Modifiers *);
53
+ void __catalyst__qis__PauliZ(QUBIT *, const Modifiers *);
54
+ void __catalyst__qis__Hadamard(QUBIT *, const Modifiers *);
55
+ void __catalyst__qis__S(QUBIT *, const Modifiers *);
56
+ void __catalyst__qis__T(QUBIT *, const Modifiers *);
57
+ void __catalyst__qis__PhaseShift(double, QUBIT *, const Modifiers *);
58
+ void __catalyst__qis__RX(double, QUBIT *, const Modifiers *);
59
+ void __catalyst__qis__RY(double, QUBIT *, const Modifiers *);
60
+ void __catalyst__qis__RZ(double, QUBIT *, const Modifiers *);
61
+ void __catalyst__qis__Rot(double, double, double, QUBIT *, const Modifiers *);
62
+ void __catalyst__qis__CNOT(QUBIT *, QUBIT *, const Modifiers *);
63
+ void __catalyst__qis__CY(QUBIT *, QUBIT *, const Modifiers *);
64
+ void __catalyst__qis__CZ(QUBIT *, QUBIT *, const Modifiers *);
65
+ void __catalyst__qis__SWAP(QUBIT *, QUBIT *, const Modifiers *);
66
+ void __catalyst__qis__IsingXX(double, QUBIT *, QUBIT *, const Modifiers *);
67
+ void __catalyst__qis__IsingYY(double, QUBIT *, QUBIT *, const Modifiers *);
68
+ void __catalyst__qis__IsingXY(double, QUBIT *, QUBIT *, const Modifiers *);
69
+ void __catalyst__qis__IsingZZ(double, QUBIT *, QUBIT *, const Modifiers *);
70
+ void __catalyst__qis__ControlledPhaseShift(double, QUBIT *, QUBIT *, const Modifiers *);
71
+ void __catalyst__qis__CRX(double, QUBIT *, QUBIT *, const Modifiers *);
72
+ void __catalyst__qis__CRY(double, QUBIT *, QUBIT *, const Modifiers *);
73
+ void __catalyst__qis__CRZ(double, QUBIT *, QUBIT *, const Modifiers *);
74
+ void __catalyst__qis__CRot(double, double, double, QUBIT *, QUBIT *, const Modifiers *);
75
+ void __catalyst__qis__CSWAP(QUBIT *, QUBIT *, QUBIT *, const Modifiers *);
76
+ void __catalyst__qis__Toffoli(QUBIT *, QUBIT *, QUBIT *, const Modifiers *);
77
+ void __catalyst__qis__MultiRZ(double, const Modifiers *, int64_t, /*qubits*/...);
78
+ void __catalyst__qis__GlobalPhase(double, const Modifiers *);
79
+ void __catalyst__qis__ISWAP(QUBIT *, QUBIT *, const Modifiers *);
80
+ void __catalyst__qis__PSWAP(double, QUBIT *, QUBIT *, const Modifiers *);
81
+
82
+ // Struct pointer arguments for these instructions represent real arguments,
83
+ // as passing structs by value is too unreliable / compiler dependant.
84
+ void __catalyst__qis__QubitUnitary(MemRefT_CplxT_double_2d *, const Modifiers *, int64_t,
85
+ /*qubits*/...);
86
+
87
+ ObsIdType __catalyst__qis__NamedObs(int64_t, QUBIT *);
88
+ ObsIdType __catalyst__qis__HermitianObs(MemRefT_CplxT_double_2d *, int64_t, /*qubits*/...);
89
+ ObsIdType __catalyst__qis__TensorObs(int64_t, /*obsKeys*/...);
90
+ ObsIdType __catalyst__qis__HamiltonianObs(MemRefT_double_1d *, int64_t, /*obsKeys*/...);
91
+
92
+ // Struct pointers arguments here represent return values.
93
+ RESULT *__catalyst__qis__Measure(QUBIT *, int32_t);
94
+ double __catalyst__qis__Expval(ObsIdType);
95
+ double __catalyst__qis__Variance(ObsIdType);
96
+ void __catalyst__qis__Probs(MemRefT_double_1d *, int64_t, /*qubits*/...);
97
+ void __catalyst__qis__Sample(MemRefT_double_2d *, int64_t, int64_t, /*qubits*/...);
98
+ void __catalyst__qis__Counts(PairT_MemRefT_double_int64_1d *, int64_t, int64_t, /*qubits*/...);
99
+ void __catalyst__qis__State(MemRefT_CplxT_double_1d *, int64_t, /*qubits*/...);
100
+ void __catalyst__qis__Gradient(int64_t, /*results*/...);
101
+ void __catalyst__qis__Gradient_params(MemRefT_int64_1d *, int64_t, /*results*/...);
102
+
103
+ void __catalyst__host__rt__unrecoverable_error();
104
+
105
+ #ifdef __cplusplus
106
+ } // extern "C"
107
+ #endif
108
+
109
+ #endif
@@ -0,0 +1,156 @@
1
+ // Copyright 2022-2023 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
+ #ifndef TYPES_H
17
+ #define TYPES_H
18
+
19
+ #include <cmath>
20
+ #include <cstdint>
21
+ #include <limits>
22
+
23
+ #ifdef __cplusplus
24
+ extern "C" {
25
+ #endif
26
+
27
+ // Qubit, Result and Observable types
28
+ struct QUBIT;
29
+ typedef intptr_t QubitIdType;
30
+
31
+ typedef bool RESULT;
32
+ typedef RESULT *Result;
33
+ typedef void *QirArray;
34
+
35
+ typedef intptr_t ObsIdType;
36
+
37
+ enum ObsId : int8_t {
38
+ Identity = 0,
39
+ PauliX,
40
+ PauliY,
41
+ PauliZ,
42
+ Hadamard,
43
+ Hermitian,
44
+ };
45
+
46
+ enum ObsType : int8_t {
47
+ Basic = 0,
48
+ TensorProd,
49
+ Hamiltonian,
50
+ };
51
+
52
+ // complex<float> type
53
+ struct CplxT_float {
54
+ float real;
55
+ float imag;
56
+ };
57
+
58
+ // complex<double> type
59
+ struct CplxT_double {
60
+ double real;
61
+ double imag;
62
+ };
63
+
64
+ enum NumericType : int8_t {
65
+ idx = 0,
66
+ i1,
67
+ i8,
68
+ i16,
69
+ i32,
70
+ i64,
71
+ f32,
72
+ f64,
73
+ c64,
74
+ c128,
75
+ };
76
+
77
+ // MemRefT<datatype, dimension=rank> type
78
+ struct OpaqueMemRefT {
79
+ int64_t rank;
80
+ void *descriptor;
81
+ NumericType datatype;
82
+ };
83
+
84
+ // MemRefT<complex<double>, dimension=1> type
85
+ struct MemRefT_CplxT_double_1d {
86
+ CplxT_double *data_allocated;
87
+ CplxT_double *data_aligned;
88
+ size_t offset;
89
+ size_t sizes[1];
90
+ size_t strides[1];
91
+ };
92
+
93
+ // MemRefT<complex<double>, dimension=2> type
94
+ struct MemRefT_CplxT_double_2d {
95
+ CplxT_double *data_allocated;
96
+ CplxT_double *data_aligned;
97
+ size_t offset;
98
+ size_t sizes[2];
99
+ size_t strides[2];
100
+ };
101
+
102
+ // MemRefT<double, dimension=1> type
103
+ struct MemRefT_double_1d {
104
+ double *data_allocated;
105
+ double *data_aligned;
106
+ size_t offset;
107
+ size_t sizes[1];
108
+ size_t strides[1];
109
+ };
110
+
111
+ // MemRefT<double, dimension=2> type
112
+ struct MemRefT_double_2d {
113
+ double *data_allocated;
114
+ double *data_aligned;
115
+ size_t offset;
116
+ size_t sizes[2];
117
+ size_t strides[2];
118
+ };
119
+
120
+ // MemRefT<int64_t, dimension=1> type
121
+ struct MemRefT_int64_1d {
122
+ int64_t *data_allocated;
123
+ int64_t *data_aligned;
124
+ size_t offset;
125
+ size_t sizes[1];
126
+ size_t strides[1];
127
+ };
128
+
129
+ // PairT<MemRefT<double, dimension=1>, MemRefT<int64, dimension=2>> type
130
+ struct PairT_MemRefT_double_int64_1d {
131
+ struct MemRefT_double_1d first;
132
+ struct MemRefT_int64_1d second;
133
+ };
134
+
135
+ // Quantum operation modifiers
136
+ struct Modifiers {
137
+ bool adjoint;
138
+ size_t num_controlled;
139
+ QUBIT *controlled_wires;
140
+ bool *controlled_values;
141
+ };
142
+
143
+ typedef struct CplxT_double CplxT_double;
144
+ typedef struct MemRefT_CplxT_double_1d MemRefT_CplxT_double_1d;
145
+ typedef struct MemRefT_CplxT_double_2d MemRefT_CplxT_double_2d;
146
+ typedef struct MemRefT_double_1d MemRefT_double_1d;
147
+ typedef struct MemRefT_double_2d MemRefT_double_2d;
148
+ typedef struct MemRefT_int64_1d MemRefT_int64_1d;
149
+ typedef struct PairT_MemRefT_double_int64_1d PairT_MemRefT_double_int64_1d;
150
+ typedef struct Modifiers Modifiers;
151
+
152
+ #ifdef __cplusplus
153
+ } // extern "C"
154
+ #endif
155
+
156
+ #endif
@@ -102,9 +102,9 @@ Prod = {}
102
102
 
103
103
  [measurement_processes]
104
104
 
105
- Expval = {}
106
- Var = {}
107
- Probs = {}
105
+ Expval = { condition = [ "analytic" ] }
106
+ Var = { condition = [ "analytic" ] }
107
+ Probs = { condition = [ "analytic" ] }
108
108
  State = { condition = [ "analytic" ] }
109
109
  Sample = { condition = [ "finiteshots" ] }
110
110
  Counts = { condition = [ "finiteshots" ] }
@@ -128,10 +128,6 @@ dynamic_qubit_management = true
128
128
  # The option key will be the key in a dictionary.
129
129
  # The string corresponds to a field queried in the `qml.Device` instance.
130
130
 
131
- # Number of qubit wires
132
- wires = "wires"
133
- # Number of shots per job
134
- shots = "shots"
135
131
  # Use "hybrid" stabilizer optimization? (Default is "true"; non-Clifford circuits will fall back to near-Clifford or universal simulation)
136
132
  is_hybrid_stabilizer = "isStabilizerHybrid"
137
133
  # Use "tensor network" optimization? (Default is "true"; prevents dynamic qubit de-allocation; might function sub-optimally with "hybrid" stabilizer enabled)
@@ -16,4 +16,4 @@
16
16
  Version number (major.minor.patch[-label])
17
17
  """
18
18
 
19
- __version__ = "0.8.1"
19
+ __version__ = "0.8.4"
@@ -40,8 +40,6 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice {
40
40
  bool oc;
41
41
  bool hp;
42
42
  bool nw;
43
- bitLenInt allocated_qubits;
44
- bitLenInt mapped_qubits;
45
43
  size_t shots;
46
44
  Qrack::QInterfacePtr qsim;
47
45
  std::map<QubitIdType, bitLenInt> qubit_map;
@@ -391,8 +389,6 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice {
391
389
  , oc(true)
392
390
  , hp(false)
393
391
  , nw(false)
394
- , allocated_qubits(0U)
395
- , mapped_qubits(0U)
396
392
  , shots(1U)
397
393
  , qsim(nullptr)
398
394
  {
@@ -403,98 +399,46 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice {
403
399
  kwargs = trim(kwargs);
404
400
 
405
401
  std::map<std::string, int> keyMap;
406
- keyMap["'wires'"] = 1;
407
- keyMap["'shots'"] = 2;
408
- keyMap["'is_hybrid_stabilizer'"] = 3;
409
- keyMap["'is_tensor_network'"] = 4;
410
- keyMap["'is_schmidt_decomposed'"] = 5;
411
- keyMap["'is_schmidt_decomposition_parallel'"] = 6;
412
- keyMap["'is_qbdd'"] = 7;
413
- keyMap["'is_gpu'"] = 8;
414
- keyMap["'is_host_pointer'"] = 9;
415
- keyMap["'is_noisy'"] = 10;
402
+ keyMap["'is_hybrid_stabilizer'"] = 1;
403
+ keyMap["'is_tensor_network'"] = 2;
404
+ keyMap["'is_schmidt_decomposed'"] = 3;
405
+ keyMap["'is_schmidt_decomposition_parallel'"] = 4;
406
+ keyMap["'is_qbdd'"] = 5;
407
+ keyMap["'is_gpu'"] = 6;
408
+ keyMap["'is_host_pointer'"] =7;
409
+ keyMap["'is_noisy'"] = 8;
416
410
 
417
411
  size_t pos;
418
412
  while ((pos = kwargs.find(":")) != std::string::npos) {
419
413
  std::string key = trim(kwargs.substr(0, pos));
420
414
  kwargs.erase(0, pos + 1U);
421
-
422
- if (key == "'wires'") {
423
- // Handle if empty
424
- // We look for ',' or npos, to respect other Wires value kwargs
425
- if (kwargs.find("<Wires = []>") != kwargs.find("<Wires = []>,")) {
426
- continue;
427
- }
428
-
429
- // Handle if integer
430
- pos = kwargs.find(",");
431
- bool isInt = true;
432
- for (size_t i = 0; i < pos; ++i) {
433
- if ((kwargs[i] != ' ') && !isdigit(kwargs[i])) {
434
- isInt = false;
435
- break;
436
- }
437
- }
438
- if (isInt) {
439
- mapped_qubits = stoi(trim(kwargs.substr(0, pos)));
440
- for (size_t i = 0U; i < mapped_qubits; ++i) {
441
- qubit_map[i] = i;
442
- }
443
- kwargs.erase(0, pos + 1U);
444
-
445
- continue;
446
- }
447
-
448
- // Handles if Wires object
449
- pos = kwargs.find("]>");
450
- std::string value = kwargs.substr(0, pos);
451
- kwargs.erase(0, pos + 3U);
452
- size_t p = value.find("[");
453
- value.erase(0, p + 1U);
454
- size_t q;
455
- while ((q = value.find(",")) != std::string::npos) {
456
- qubit_map[(QubitIdType)stoi(trim(value.substr(0, q)))] = mapped_qubits;
457
- ++mapped_qubits;
458
- value.erase(0, q + 1U);
459
- }
460
- qubit_map[stoi(trim(value))] = mapped_qubits;
461
- ++mapped_qubits;
462
-
463
- continue;
464
- }
465
-
466
415
  pos = kwargs.find(",");
467
416
  std::string value = trim(kwargs.substr(0, pos));
468
417
  kwargs.erase(0, pos + 1U);
469
418
  const bool val = (value == "True");
470
419
  switch (keyMap[key]) {
471
- case 2:
472
- if (value != "None") {
473
- shots = std::stoi(value);
474
- }
475
- break;
476
- case 3:
420
+ case 1:
477
421
  sh = val;
478
422
  break;
479
- case 4:
423
+ case 2:
480
424
  tn = val;
481
425
  break;
482
- case 5:
426
+ case 3:
483
427
  sd = val;
484
428
  break;
485
- case 6:
429
+ case 4:
486
430
  md = val;
487
431
  break;
488
- case 7:
432
+ case 5:
489
433
  bdt = val;
490
434
  break;
491
- case 8:
435
+ case 6:
492
436
  oc = val;
493
437
  break;
494
- case 9:
438
+ case 7:
495
439
  hp = val;
496
440
  break;
497
- case 10:
441
+ case 8:
498
442
  nw = val;
499
443
  break;
500
444
  default:
@@ -511,16 +455,8 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice {
511
455
  QrackDevice &operator=(QuantumDevice &&) = delete;
512
456
 
513
457
  auto AllocateQubit() -> QubitIdType override {
514
- if (allocated_qubits >= qubit_map.size()) {
515
- throw std::runtime_error("Catalyst has requested more qubits than exist in device, with "
516
- + std::to_string(allocated_qubits) + " allocated qubits. "
517
- + "(Set your wires count high enough, for the device.)");
518
- }
458
+ const QubitIdType label = qsim->GetQubitCount();
519
459
  qsim->Allocate(1U);
520
- auto it = qubit_map.begin();
521
- std::advance(it, allocated_qubits);
522
- const QubitIdType label = it->first;
523
- ++allocated_qubits;
524
460
  return label;
525
461
  }
526
462
  auto AllocateQubits(size_t num_qubits) -> std::vector<QubitIdType> override {
@@ -590,13 +526,11 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice {
590
526
  qsim->M(id);
591
527
  // Deallocate
592
528
  qsim->Dispose(id, 1U);
593
- --allocated_qubits;
594
529
  }
595
530
  void ReleaseAllQubits() override
596
531
  {
597
532
  // State vector is left empty
598
533
  qsim = QSIM_CONFIG(0U);
599
- allocated_qubits = 0;
600
534
  }
601
535
  [[nodiscard]] auto GetNumQubits() const -> size_t override
602
536
  {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pennylane-qrack
3
- Version: 0.8.1
3
+ Version: 0.8.4
4
4
  Summary: PennyLane plugin for Qrack.
5
5
  Home-page: http://github.com/vm6502q
6
6
  Maintainer: vm6502q
@@ -6,9 +6,15 @@ Makefile
6
6
  README.rst
7
7
  requirements.txt
8
8
  setup.py
9
+ catalyst/runtime/include/DataView.hpp
10
+ catalyst/runtime/include/Exception.hpp
11
+ catalyst/runtime/include/QuantumDevice.hpp
12
+ catalyst/runtime/include/RuntimeCAPI.h
13
+ catalyst/runtime/include/Types.h
9
14
  pennylane_qrack/QrackDeviceConfig.toml
10
15
  pennylane_qrack/__init__.py
11
16
  pennylane_qrack/_version.py
17
+ pennylane_qrack/libqrack_device.so
12
18
  pennylane_qrack/qrack_device.cpp
13
19
  pennylane_qrack/qrack_device.py
14
20
  pennylane_qrack.egg-info/PKG-INFO
File without changes