Skip to content

Commit a213eef

Browse files
isaacdevlugtlazypanda10117
authored andcommitted
1 parent 6668f07 commit a213eef

File tree

1 file changed

+64
-100
lines changed

1 file changed

+64
-100
lines changed

doc/releases/changelog-dev.md

Lines changed: 64 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
[(#2002)](https://github.com/PennyLaneAI/catalyst/pull/2002)
1515

1616
Two new functions, ``qml.allocate()`` and ``qml.deallocate()``, [have been added to
17-
PennyLane](https://docs.pennylane.ai/en/stable/development/release_notes.html#release-0-43-0) to support
18-
dynamic wire allocation. With Catalyst, these features can be accessed on
17+
PennyLane](https://docs.pennylane.ai/en/stable/development/release_notes.html#release-0-43-0)
18+
to support dynamic wire allocation. With Catalyst, these features can be accessed on
1919
``lightning.qubit``, ``lightning.kokkos``, and ``lightning.gpu``.
2020

2121
Dynamic wire allocation refers to the allocation of wires in the middle of a circuit, as opposed to the static allocation during device initialization. For example:
@@ -26,126 +26,89 @@
2626
@qjit
2727
@qml.qnode(qml.device("lightning.qubit", wires=3)) # 3 initial qubits
2828
def circuit():
29-
qml.X(1) # |010>
29+
qml.X(0) # |10>
3030

31-
with qml.allocate(1) as q: # |010> and |0>, 1 dynamically allocted qubit
32-
qml.X(q[0]) # |010> and |1>
33-
qml.CNOT(wires=[q[0], 2]) # |011> and |1>
31+
with qml.allocate(1) as q: # |10> and |0>, 1 dynamically allocated qubit
32+
qml.X(q[0]) # |10> and |1>
33+
qml.CNOT(wires=[q[0], 1]) # |11> and |1>
3434

3535
return qml.probs(wires=[0, 1, 2])
36-
37-
qml.capture.disable()
3836
```
3937

4038
```pycon
4139
>>> print(circuit())
42-
[0. 0. 0. 1. 0. 0. 0. 0.]
43-
```
44-
45-
In the above program, 3 qubits are allocated during device initialization, and 1
46-
additional qubit is allocated inside the circuit with ``qml.allocate(1)``. This is clear
47-
when we inspect the compiled MLIR:
48-
49-
```
50-
>>> print(circuit.mlir)
51-
func.func public @circuit() -> tensor<8xf64> attributes {qnode} {
52-
%c0_i64 = arith.constant 0 : i64
53-
quantum.device shots(%c0_i64) ["/path/to/liblightning_qubit_catalyst.so", "LightningSimulator", "{'mcmc': False, 'num_burnin': 0, 'kernel_name': None}"]
54-
%0 = quantum.alloc( 3) : !quantum.reg
55-
%1 = quantum.extract %0[ 1] : !quantum.reg -> !quantum.bit
56-
%out_qubits = quantum.custom "PauliX"() %1 : !quantum.bit
57-
%2 = quantum.alloc( 1) : !quantum.reg
58-
%3 = quantum.extract %2[ 0] : !quantum.reg -> !quantum.bit
59-
%out_qubits_0 = quantum.custom "PauliX"() %3 : !quantum.bit
60-
%4 = quantum.extract %0[ 2] : !quantum.reg -> !quantum.bit
61-
%out_qubits_1:2 = quantum.custom "CNOT"() %out_qubits_0, %4 : !quantum.bit, !quantum.bit
62-
%5 = quantum.insert %2[ 0], %out_qubits_1#0 : !quantum.reg, !quantum.bit
63-
quantum.dealloc %5 : !quantum.reg
64-
%6 = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit
65-
%7 = quantum.compbasis qubits %6, %out_qubits, %out_qubits_1#1 : !quantum.obs
66-
%8 = quantum.probs %7 : tensor<8xf64>
67-
%9 = quantum.insert %0[ 1], %out_qubits : !quantum.reg, !quantum.bit
68-
%10 = quantum.insert %9[ 2], %out_qubits_1#1 : !quantum.reg, !quantum.bit
69-
%11 = quantum.insert %10[ 0], %6 : !quantum.reg, !quantum.bit
70-
quantum.dealloc %11 : !quantum.reg
71-
quantum.device_release
72-
return %8 : tensor<8xf64>
73-
}
40+
[0. 0. 0. 1.]
7441
```
7542

76-
We can see that there are now 2 pairs of ``quantum.alloc`` and ``quantum.dealloc``
77-
operations. The quantum register value ``%0`` corresponds to the initial wires on the
78-
device, and the quantum register value ``%2`` corresponds to the dynamically allocated
79-
wire.
43+
In the above program, 2 qubits are allocated during device initialization, and 1
44+
additional qubit is allocated inside the circuit with ``qml.allocate(1)``.
8045

8146
For more information on what ``qml.allocate`` and ``qml.deallocate`` do, please consult the
8247
[PennyLane v0.43 release notes](https://docs.pennylane.ai/en/stable/development/release_notes.html#release-0-43-0).
8348

8449
However, there are some notable differences between the behaviour of these features
85-
with ``qjit`` versus without. For details, please see
86-
[the relevant sections on the Catalyst sharp bits page](https://docs.pennylane.ai/projects/catalyst/en/stable/dev/sharp_bits.html#functionality-differences-from-pennylane).
50+
with ``qjit`` versus without. For details, please see the relevant sections in the
51+
[Catalyst sharp bits page](https://docs.pennylane.ai/projects/catalyst/en/stable/dev/sharp_bits.html#functionality-differences-from-pennylane).
8752

8853
* A new quantum compilation pass that reduces the depth and count of non-Clifford Pauli product
8954
rotations (PPRs) in circuits is now available. This compilation pass works by commuting
90-
non-Clifford PPRs (often referred to as ``T`` gates) in adjacent
55+
non-Clifford PPRs (often just referred to as ``T`` gates) in adjacent
9156
layers and merging compatible ones. More details can be found in Figure 6 of
9257
[A Game of Surface Codes](https://arXiv:1808.02892v3).
9358
[(#1975)](https://github.com/PennyLaneAI/catalyst/pull/1975)
9459
[(#2048)](https://github.com/PennyLaneAI/catalyst/pull/2048)
9560

96-
Consider the following circuit.
61+
Consider the following circuit:
9762

9863
```python
9964
import pennylane as qml
10065
from catalyst import qjit, measure
101-
from catalyst.passes import to_ppr, commute_ppr, t_layer_reduction, merge_ppr_ppm
66+
from catalyst.passes import to_ppr, commute_ppr, t_layer_reduction, merge_ppr_ppm, ppm_specs
10267

10368
pips = [("pipe", ["enforce-runtime-invariants-pipeline"])]
10469

70+
no_reduce_T = {
71+
"to_ppr": {},
72+
"commute_ppr": {},
73+
"merge_ppr_ppm": {},
74+
}
10575

106-
@qjit(pipelines=pips, target="mlir")
107-
@t_layer_reduction
108-
@merge_ppr_ppm
109-
@commute_ppr
110-
@to_ppr
111-
@qml.qnode(qml.device("null.qubit", wires=3))
112-
def circuit():
113-
for i in range(3):
114-
qml.H(wires=i)
115-
qml.S(wires=i)
116-
qml.CNOT(wires=[i, (i + 1) % n])
117-
qml.T(wires=i)
118-
qml.H(wires=i)
119-
qml.T(wires=i)
120-
121-
return [measure(wires=i) for i in range(n)]
122-
```
76+
reduce_T = {
77+
"to_ppr": {},
78+
"commute_ppr": {},
79+
"merge_ppr_ppm": {},
80+
"t_layer_reduction": {}
81+
}
12382

124-
After performing the ``catalyst.passes.to_ppr`` and ``catalyst.passes.merge_ppr_ppm``
125-
passes, the circuit contains a depth of four of non-Clifford PPRs. Subsequently applying the
126-
``t_layer_reduction`` pass will move PPRs around via commutation, resulting in a circuit with a
127-
smaller PPR depth of three.
83+
for pipeline in [reduce_T, no_reduce_T]:
84+
85+
@qjit(pipelines=pips, target="mlir", circuit_transform_pipeline=pipeline)
86+
@qml.qnode(qml.device("null.qubit", wires=3))
87+
def circuit():
88+
n = 3
89+
for i in range(n):
90+
qml.H(wires=i)
91+
qml.S(wires=i)
92+
qml.CNOT(wires=[i, (i + 1) % n])
93+
qml.T(wires=i)
94+
qml.H(wires=i)
95+
qml.T(wires=i)
96+
97+
return [measure(wires=i) for i in range(n)]
98+
99+
print(ppm_specs(circuit))
100+
```
128101

129102
```pycon
130-
>>> print(circuit.mlir_opt)
131-
...
132-
%1 = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit
133-
%2 = quantum.extract %0[ 1] : !quantum.reg -> !quantum.bit
134-
// layer 1
135-
%3 = qec.ppr ["X"](8) %1 : !quantum.bit
136-
%4 = qec.ppr ["X"](8) %2 : !quantum.bit
137-
138-
// layer 2
139-
%5 = quantum.extract %0[ 2] : !quantum.reg -> !quantum.bit
140-
%6:2 = qec.ppr ["Y", "X"](8) %3, %4 : !quantum.bit, !quantum.bit
141-
%7 = qec.ppr ["X"](8) %5 : !quantum.bit
142-
%8:3 = qec.ppr ["X", "Y", "X"](8) %6#0, %6#1, %7:!quantum.bit, !quantum.bit, !quantum.bit
143-
144-
// layer 3
145-
%9:3 = qec.ppr ["X", "X", "Y"](8) %8#0, %8#1, %8#2:!quantum.bit, !quantum.bit, !quantum.bit
146-
...
103+
{'circuit_0': {'depth_pi8_ppr': 3, 'depth_ppm': 1, 'logical_qubits': 3, 'max_weight_pi8': 3, 'num_of_ppm': 3, 'pi8_ppr': 6}}
104+
{'circuit_0': {'depth_pi8_ppr': 4, 'depth_ppm': 1, 'logical_qubits': 3, 'max_weight_pi8': 3, 'num_of_ppm': 3, 'pi8_ppr': 6}}
147105
```
148106

107+
After performing the :func:`~.passes.to_ppr`, :func:`~.passes.commute_ppr`, and :func:`~.passes.merge_ppr_ppm`,
108+
passes, the circuit contains a depth of four of non-Clifford PPRs (`depth_pi8_ppr`). Subsequently applying the
109+
:func:`~.passes.t_layer_reduction` pass will move PPRs around via commutation, resulting in a circuit with a
110+
smaller PPR depth of three.
111+
149112
* Catalyst now provides native support for `SingleExcitation`, `DoubleExcitation`,
150113
and `PCPhase` on compatible devices like Lightning simulators.
151114
This enhancement avoids unnecessary gate decomposition,
@@ -165,14 +128,6 @@
165128
return qml.probs()
166129
```
167130

168-
<h3>Improvements 🛠</h3>
169-
170-
* Significantly improved resource tracking with `null.qubit`.
171-
The new tracking has better integration with PennyLane (e.g. for passing the filename to write out), cleaner documentation, and its own wrapper class.
172-
It also now tracks circuit depth, as well as gate counts by number of wires.
173-
[(#2033)](https://github.com/PennyLaneAI/catalyst/pull/2033)
174-
[(#2055)](https://github.com/PennyLaneAI/catalyst/pull/2055)
175-
176131
* Catalyst now supports returning classical and MCM values with the dynamic one-shot MCM method.
177132
[(#2004)](https://github.com/PennyLaneAI/catalyst/pull/2004) [(#2090)](https://github.com/PennyLaneAI/catalyst/pull/2090)
178133

@@ -202,13 +157,21 @@
202157
True], dtype=bool))
203158
```
204159

205-
* Improve the pass `--ppm-specs` to count the depth of PPRs and PPMs in the circuit.
206-
[(#2014)](https://github.com/PennyLaneAI/catalyst/pull/2014)
207-
208160
* The default mid-circuit measurement method in catalyst has been changed from `"single-branch-statistics"` to `"one-shot"`.
209161
[[#2017]](https://github.com/PennyLaneAI/catalyst/pull/2017)
210162
[[#2019]](https://github.com/PennyLaneAI/catalyst/pull/2019)
211163

164+
<h3>Improvements 🛠</h3>
165+
166+
* Significantly improved resource tracking with `null.qubit`.
167+
The new tracking has better integration with PennyLane (e.g. for passing the filename to write out), cleaner documentation, and its own wrapper class.
168+
It also now tracks circuit depth, as well as gate counts by number of wires.
169+
[(#2033)](https://github.com/PennyLaneAI/catalyst/pull/2033)
170+
[(#2055)](https://github.com/PennyLaneAI/catalyst/pull/2055)
171+
172+
* Improve the pass `--ppm-specs` to count the depth of PPRs and PPMs in the circuit.
173+
[(#2014)](https://github.com/PennyLaneAI/catalyst/pull/2014)
174+
212175
* A new pass `--partition-layers` has been added to group PPR/PPM operations into `qec.layer`
213176
operations based on qubit interactive and commutativity, enabling circuit analysis and
214177
potentially to support parallel execution.
@@ -324,8 +287,9 @@
324287

325288
<h3>Deprecations 👋</h3>
326289

327-
* Deprecated usages of `Device.shots` along with setting `device(..., shots=...)`.
290+
* Deprecated usages of ``Device.shots`` along with setting ``device(..., shots=...)``.
328291
Heavily adjusted frontend pipelines within qfunc, tracer, verification and QJITDevice to account for this change.
292+
Please use ``qml.set_shots(shots=...)`` or set shots at the QNode level (i.e., ``qml.QNode(..., shots=...)``).
329293
[(#1952)](https://github.com/PennyLaneAI/catalyst/pull/1952)
330294

331295
<h3>Bug fixes 🐛</h3>
@@ -485,7 +449,7 @@ for example the one-shot mid circuit measurement transform.
485449
[(#2057)](https://github.com/PennyLaneAI/catalyst/pull/2057)
486450

487451
This pass is part of a bottom-of-stack MBQC execution pathway, with a thin shim between the
488-
PPR/PPM layer and MBQC to enable end-to-end compilation on a mocked backend. Also, in MBQC gate
452+
PPR/PPM layer and MBQC to enable end-to-end compilation on a mocked backend. Also, in an MBQC gate
489453
set, one of the gate `RotXZX` cannot yet be executed on available backends.
490454

491455
```python

0 commit comments

Comments
 (0)