You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Document the semantics of the QuantumDevice interface (#1680)
This PR adds detailed descriptions of the semantics of each method in
the `QuantumDevice` interface used by runtime plugins. **Looking for
feedback on**:
- whether the semantics make sense as written (mostly they are
describing the existing behaviour in particular w.r.t to the lighting
devices)
- which methods should be considered optional - I gave it my best guest
about what a "minimal" working device would need to support
- whether anything is missing
- whether any TODOs should be implemented right now
- At the very least I would say we should remove `shots` from MP
signatures, since that was officially deprecated.
- I would say removing the `One`/`Zero` can also be at the top of the
list, since we already don't use them, and the functions to make use of
them are already gone (like `__quantum__rt__compare_result`), so they
really don't make any sense anymore.
- Some of the type restructuring might also be nice.
closes#1512
[sc-81294]
While writing these, I identified the following TODOs to improve the
interface (possibly at a later date):
```
////////////////////
////// TODO //////
////////////////////
/*
* - Remove the `shots` parameter from sample and counts methods, as that has already been
* deprecated in #1310.
* - Revisit confusing or inconsistent type usage and/or naming in the runtime/device interface:
* - QUBIT type: `QUBIT` (undefined struct) vs `QUBIT*` vs `QubitIdType`
* - RESULT type: `RESULT` (bool) vs `Result` (RESULT*)
* - OBS type: `ObsId` vs `ObsIdType`
* - Remove default argument values from the interface.
* - Include types only where they are needed:
* - CAPI types in the CAPI header
* - Runtime types in CAPI implementation or QuantumDevice header
* - Also: Should the QuantumDevice interface use the concrete C++ types instead of the type aliases?
* The former might make it clearer for any implementers what types are used.
* - Revisit instructions in the QuantumDevice interface:
* - move `PrintState` into the runtime or eliminate entirely?
* Seems unnecessary as a dedicated function since one can just call `State` + print.
* - remove `Result` specific functions (`One`, `Zero`, `compare_result` - already gone I guess)?
* With results being forced as `bool*`, there is no reason to keep these functions.
* Originally they were meant to allow an arbitrary representation of measurement results,
* and would thus require special runtime functions, but this is not the case.
* - revisit qubit management functions
* - ideally as part of dynamic allocation or multiple register support
* - several inconsistencies here, but first and foremost `AllocateQubits` has no counterpart,
* only `ReleaseAllQubits`
* - QubitUnitary / Hermitian: why creating `vector<complex>` instead of forwarding a `DataView`?
* - Why is Jacobian in `Gradient` a `vector<buffer>` instead of a 2D buffer?
* - With `Probs` / `PartialProbs` and similar ops, there are separate instructions for acting on a subsystem,
* but with `Gradient` the same function is reused for both (dictated by the `trainParams` argument`).
*
* Important: All devices need to be updated after such interface changes!
*/
```
In addition to implementing the ``QuantumDevice`` class, one must implement an entry point for the
@@ -115,8 +84,7 @@ Python devices" section further down for details.
115
84
116
85
``CustomDevice(kwargs)`` serves as a constructor for your custom device, with ``kwargs``
117
86
as a string of device specifications and options, represented in Python dictionary format.
118
-
An example could be the default number of device shots, encoded as the following string:
119
-
``"{'shots': 1000}"``.
87
+
An example could be some noise parameter or other configurable behaviour: ``"{'noise': 0.5}"``.
120
88
121
89
Note that these parameters are automatically initialized in the frontend if the library is
122
90
provided as a PennyLane plugin device (see :func:`qml.device() <pennylane.device>`).
@@ -125,14 +93,15 @@ The destructor of ``CustomDevice`` will be automatically called by the runtime.
125
93
126
94
.. warning::
127
95
128
-
This interface might change quickly in the near future.
129
-
Please check back regularly for updates and to ensure your device is compatible with
130
-
a specific version of Catalyst.
96
+
This interface might change quickly in the near future, but breaking changes will be announced
97
+
in release changelogs. Please check back regularly for updates and to ensure your device is
98
+
compatible with a specific version of Catalyst.
131
99
132
100
How to compile custom devices
133
101
=============================
134
102
135
-
One can follow the ``catalyst/runtime/tests/third_party/CMakeLists.txt`` `as an example. <https://github.com/PennyLaneAI/catalyst/blob/26b412b298f22565fea529d2019554e7ad9b9624/runtime/tests/third_party/CMakeLists.txt>`_
103
+
One can follow the ``catalyst/runtime/tests/third_party/CMakeLists.txt``
104
+
`as an example <https://github.com/PennyLaneAI/catalyst/blob/26b412b298f22565fea529d2019554e7ad9b9624/runtime/tests/third_party/CMakeLists.txt>`_.
136
105
137
106
.. code-block:: cmake
138
107
@@ -153,11 +122,17 @@ Integration with Python devices
153
122
There are two things that are needed in order to integrate with PennyLane devices:
154
123
155
124
* Adding a ``get_c_interface`` method to your ``qml.devices.Device`` class.
156
-
* Adding a ``config_filepath`` class variable pointing to your configuration file. This file should be a `toml file <https://toml.io/en/>`_ with fields that describe what gates and features are supported by your device.
157
-
* Optionally, adding a ``device_kwargs`` dictionary for runtime parameters to pass from the PennyLane device to the ``QuantumDevice`` upon initialization.
158
-
159
-
If you already have a custom PennyLane device defined in Python and have added a shared object that corresponds to your implementation of the ``QuantumDevice`` class, then all you need to do is to add a ``get_c_interface`` method to your PennyLane device.
160
-
The ``get_c_interface`` method should be a static method that takes no parameters and returns the complete path to your shared library with the ``QuantumDevice`` implementation.
125
+
* Adding a ``config_filepath`` class variable pointing to your configuration file. This file should
126
+
be a `toml file <https://toml.io/en/>`_ with fields that describe what gates and features are
127
+
supported by your device.
128
+
* Optionally, adding a ``device_kwargs`` dictionary for runtime parameters to pass from the
129
+
PennyLane device to the ``QuantumDevice`` upon initialization.
130
+
131
+
If you already have a custom PennyLane device defined in Python and have added a shared object that
132
+
corresponds to your implementation of the ``QuantumDevice`` class, then all you need to do is to add
133
+
a ``get_c_interface`` method to your PennyLane device. The ``get_c_interface`` method should be a
134
+
static method that takes no parameters and returns the complete path to your shared library with the
Instead of enabling program capture with Catalyst via `qjit(experimental_capture=True)`, program capture
23
-
can be enabled via the global toggle `qml.capture.enable()`:
24
-
40
+
Instead of enabling program capture with Catalyst via `qjit(experimental_capture=True)`, program
41
+
capture can be enabled via the global toggle `qml.capture.enable()`:
42
+
25
43
```python
26
44
import pennylane as qml
27
45
from catalyst import qjit
@@ -42,7 +60,8 @@
42
60
43
61
Disabling program capture can be done with `qml.capture.disable()`.
44
62
45
-
* The `ppr_to_ppm` pass has been renamed to `merge_ppr_ppm` (same functionality). A new `ppr_to_ppm` will handle direct decomposition of PPRs into PPMs.
63
+
* The `ppr_to_ppm` pass has been renamed to `merge_ppr_ppm` (same functionality). A new `ppr_to_ppm`
64
+
will handle direct decomposition of PPRs into PPMs.
This runtime stub is currently for mock execution only and should be treated as a placeholder
81
101
operation. Internally, it functions just as a computational-basis measurement instruction.
82
102
83
-
* The utility function `EnsureFunctionDeclaration` is refactored into the `Utils` of the `Catalyst` dialect, instead of being duplicated in each individual dialect.
103
+
* The utility function `EnsureFunctionDeclaration` is refactored into the `Utils` of the `Catalyst`
104
+
dialect, instead of being duplicated in each individual dialect.
0 commit comments