@@ -64,11 +64,10 @@ _Output_:
64
64
For creation of a circuit through Python, the ` CircuitBuilder ` can be used accordingly:
65
65
66
66
``` python
67
- from opensquirrel import CircuitBuilder
68
- from opensquirrel.ir import Float
67
+ from opensquirrel.circuit_builder import CircuitBuilder
69
68
70
69
builder = CircuitBuilder(qubit_register_size = 2 )
71
- builder.Ry(0 , Float( 0.23 ) ).CNOT(0 , 1 )
70
+ builder.Ry(0 , 0.23 ).CNOT(0 , 1 )
72
71
qc = builder.to_circuit()
73
72
74
73
print (qc)
@@ -85,6 +84,8 @@ _Output_:
85
84
You can naturally use the functionalities available in Python to create your circuit:
86
85
87
86
``` python
87
+ from opensquirrel.circuit_builder import CircuitBuilder
88
+
88
89
builder = CircuitBuilder(qubit_register_size = 10 )
89
90
for i in range (0 , 10 , 2 ):
90
91
builder.H(i)
@@ -107,6 +108,8 @@ _Output_:
107
108
For instance, you can generate a quantum fourier transform (QFT) circuit as follows:
108
109
109
110
``` python
111
+ from opensquirrel.circuit_builder import CircuitBuilder
112
+
110
113
qubit_register_size = 5
111
114
builder = CircuitBuilder(qubit_register_size)
112
115
for i in range (qubit_register_size):
@@ -144,6 +147,8 @@ _Output_:
144
147
As you can see, gates require _ strong types_ . For instance, you cannot do:
145
148
146
149
``` python
150
+ from opensquirrel.circuit import Circuit
151
+
147
152
try :
148
153
Circuit.from_string(
149
154
"""
@@ -160,13 +165,13 @@ _Output_:
160
165
161
166
Parsing error: failed to resolve overload for cnot with argument pack (qubit, int)
162
167
163
- The issue is that the CNOT expects a qubit as second input argument where an integer has been provided.
168
+ The issue is that the ` CNOT ` expects a qubit as second input argument where an integer has been provided.
164
169
165
170
## Modifying a circuit
166
171
167
172
### Merging single qubit gates
168
173
169
- All single-qubit gates appearing in a circuit can be merged by applying ` merge_single_qubit_gates( )` to the circuit.
174
+ All single-qubit gates appearing in a circuit can be merged by applying ` merge(merger=SingleQubitGatesMerger() )` to the circuit.
170
175
Note that multi-qubit gates remain untouched and single-qubit gates are not merged across any multi-qubit gates.
171
176
The gate that results from the merger of single-qubit gates will, in general,
172
177
comprise an arbitrary rotation and, therefore, not be a known gate.
@@ -182,14 +187,17 @@ the semantic representation of the anonymous gate is exported.
182
187
will not recognize it as a valid statement.
183
188
184
189
``` python
190
+ from opensquirrel.circuit_builder import CircuitBuilder
191
+ from opensquirrel.passes.merger import SingleQubitGatesMerger
192
+ from opensquirrel.ir import Float
185
193
import math
186
194
187
195
builder = CircuitBuilder(1 )
188
196
for _ in range (4 ):
189
- builder.Rx(0 , Float( math.pi / 4 ) )
197
+ builder.Rx(0 , math.pi / 4 )
190
198
qc = builder.to_circuit()
191
199
192
- qc.merge_single_qubit_gates( )
200
+ qc.merge( merger = SingleQubitGatesMerger() )
193
201
194
202
print (qc)
195
203
```
@@ -222,6 +230,9 @@ It accepts a qubit, an axis, an angle, and a phase as arguments.
222
230
Below is shown how the X-gate is defined in the default gate set of OpenSquirrel:
223
231
224
232
``` python
233
+ from opensquirrel.ir import Gate, BlochSphereRotation, QubitLike, named_gate
234
+ import math
235
+
225
236
@named_gate
226
237
def x (q : QubitLike) -> Gate:
227
238
return BlochSphereRotation(qubit = q, axis = (1 , 0 , 0 ), angle = math.pi, phase = math.pi / 2 )
@@ -232,17 +243,22 @@ This _tells_ OpenSquirrel that the function defines a gate and that it should,
232
243
therefore, have all the nice properties OpenSquirrel expects of it.
233
244
234
245
- The ` ControlledGate ` class is used to define a multiple qubit gate that comprises a controlled operation.
235
- For instance, the CNOT gate is defined in the default gate set of OpenSquirrel as follows:
246
+ For instance, the ` CNOT ` gate is defined in the default gate set of OpenSquirrel as follows:
236
247
237
248
``` python
249
+ from opensquirrel.ir import Gate, ControlledGate, QubitLike, named_gate
250
+ from opensquirrel import X
251
+
238
252
@named_gate
239
253
def cnot (control : QubitLike, target : QubitLike) -> Gate:
240
- return ControlledGate(control, x (target))
254
+ return ControlledGate(control, X (target))
241
255
```
242
256
243
257
- The ` MatrixGate ` class may be used to define a gate in the generic form of a matrix:
244
258
245
259
``` python
260
+ from opensquirrel.ir import Gate, MatrixGate, QubitLike, named_gate
261
+
246
262
@named_gate
247
263
def swap (q1 : QubitLike, q2 : QubitLike) -> Gate:
248
264
return MatrixGate(
@@ -274,13 +290,14 @@ Decompositions can be:
274
290
#### 1. Predefined decomposition
275
291
276
292
The first kind of decomposition is when you want to replace a particular gate in the circuit,
277
- like the CNOT gate, with a fixed list of gates.
278
- It is commonly known that CNOT can be decomposed as H-CZ-H .
293
+ like the ` CNOT ` gate, with a fixed list of gates.
294
+ It is commonly known that ` CNOT ` can be decomposed as ` H ` - ` CZ ` - ` H ` .
279
295
This decomposition is demonstrated below using a Python _ lambda function_ ,
280
296
which requires the same parameters as the gate that is decomposed:
281
297
282
298
``` python
283
- from opensquirrel.default_gates import CNOT , H, CZ
299
+ from opensquirrel.circuit import Circuit
300
+ from opensquirrel import CNOT , H, CZ
284
301
285
302
qc = Circuit.from_string(
286
303
"""
@@ -323,6 +340,9 @@ For instance, an exception is thrown if we forget the final Hadamard,
323
340
or H gate, in our custom-made decomposition:
324
341
325
342
``` python
343
+ from opensquirrel.circuit import Circuit
344
+ from opensquirrel import CNOT , CZ , H
345
+
326
346
qc = Circuit.from_string(
327
347
"""
328
348
version 3.0
@@ -349,21 +369,42 @@ _Output_:
349
369
350
370
replacement for gate CNOT does not preserve the quantum state
351
371
372
+ ##### _ ` CNOT ` to ` CZ ` decomposer_
373
+
374
+ The decomposition of the ` CNOT ` gate into a ` CZ ` gate (with additional single-qubit gates) is used frequently.
375
+ To this end a ` CNOT2CZDecomposer ` has been implemented that decomposes any ` CNOT ` s in a circuit to a
376
+ ` Ry(-π/2) ` -` CZ ` -` Ry(π/2) ` . The decomposition is illustrated in the image below.
377
+
378
+ <p align =" center " > <img width =" 600 " src =" _static/cnot2cz.png " > </p >
379
+
380
+ ` Ry ` gates are used instead of, _ e.g._ , ` H ` gates, as they are, generally,
381
+ more likely to be supported already by target backends.
382
+
383
+ ##### _ ` SWAP ` to ` CNOT ` decomposer_
384
+
385
+ The ` SWAP2CNOTDecomposer ` implements the predefined decomposition of the ` SWAP ` gate into 3 ` CNOT ` gates.
386
+ The decomposition is illustrated in the image below.
387
+
388
+ <p align =" center " > <img width =" 600 " src =" _static/swap2cnot.png " > </p >
389
+
390
+
352
391
#### 2. Inferred decomposition
353
392
354
393
OpenSquirrel has a variety inferred decomposition strategies.
355
394
More in depth tutorials can be found in the [ decomposition example Jupyter notebook] ( https://github.com/QuTech-Delft/OpenSquirrel/blob/develop/example/decompositions.ipynb ) .
356
395
357
- One of the most common single qubit decomposition techniques is the Z-Y-Z decomposition.
396
+ One of the most common single qubit decomposition techniques is the ZYZ decomposition.
358
397
This technique decomposes a quantum gate into an ` Rz ` , ` Ry ` and ` Rz ` gate in that order.
359
- The decompositions are found in ` opensquirrel.decomposer ` ,
360
- an example can be seen below where a Hadamard, Z, Y and Rx gate are all decomposed on a single qubit circuit.
398
+ The decompositions are found in ` opensquirrel.passes. decomposer ` ,
399
+ an example can be seen below where a ` H ` , ` Z ` , ` Y ` , and ` Rx ` gate are all decomposed on a single qubit circuit.
361
400
362
401
``` python
363
- from opensquirrel.decomposer.aba_decomposer import ZYZDecomposer
402
+ from opensquirrel.circuit_builder import CircuitBuilder
403
+ from opensquirrel.passes.decomposer import ZYZDecomposer
404
+ import math
364
405
365
406
builder = CircuitBuilder(qubit_register_size = 1 )
366
- builder.H(0 ).Z(0 ).Y(0 ).Rx(0 , Float( math.pi / 3 ) )
407
+ builder.H(0 ).Z(0 ).Y(0 ).Rx(0 , math.pi / 3 )
367
408
qc = builder.to_circuit()
368
409
369
410
qc.decompose(decomposer = ZYZDecomposer())
@@ -387,8 +428,8 @@ _Output_:
387
428
Similarly, the decomposer can be used on individual gates.
388
429
389
430
``` python
390
- from opensquirrel.decomposer.aba_decomposer import XZXDecomposer
391
- from opensquirrel.default_gates import H
431
+ from opensquirrel.passes.decomposer import ZYZDecomposer
432
+ from opensquirrel import H
392
433
393
434
print (ZYZDecomposer().decompose(H(0 )))
394
435
```
0 commit comments