Skip to content

Commit a6a1bfd

Browse files
authored
Make QASM as consistent as possible (quantumlib#5366)
1 parent 5fcd5d0 commit a6a1bfd

File tree

3 files changed

+109
-16
lines changed

3 files changed

+109
-16
lines changed

cirq/circuits/qasm_output_test.py

+42-2
Original file line numberDiff line numberDiff line change
@@ -270,19 +270,39 @@ def __repr__(self):
270270
return 'DummyCompositeOperation()'
271271

272272
return (
273+
cirq.I(q0),
273274
cirq.Z(q0),
274275
cirq.Z(q0) ** 0.625,
276+
cirq.Z(q0) ** 0,
275277
cirq.Y(q0),
276278
cirq.Y(q0) ** 0.375,
279+
cirq.Y(q0) ** 0,
277280
cirq.X(q0),
278281
cirq.X(q0) ** 0.875,
279-
cirq.H(q1),
282+
cirq.X(q0) ** 0,
283+
cirq.H(q0),
284+
cirq.H(q0) ** 0,
280285
cirq.X(q0) ** 0.5,
281286
cirq.X(q0) ** -0.5,
287+
cirq.S(q0),
288+
cirq.Z(q0) ** -0.5,
289+
cirq.T(q0),
290+
cirq.Z(q0) ** -0.25,
291+
cirq.Rx(rads=np.pi)(q0),
292+
cirq.Rx(rads=np.pi / 2)(q0),
293+
cirq.Rx(rads=np.pi / 4)(q0),
294+
cirq.Ry(rads=np.pi)(q0),
295+
cirq.Ry(rads=np.pi / 2)(q0),
296+
cirq.Ry(rads=np.pi / 4)(q0),
297+
cirq.Rz(rads=np.pi)(q0),
298+
cirq.Rz(rads=np.pi / 2)(q0),
299+
cirq.Rz(rads=np.pi / 4)(q0),
282300
cirq.CZ(q0, q1),
283301
cirq.CZ(q0, q1) ** 0.25, # Requires 2-qubit decomposition
284302
cirq.CNOT(q0, q1),
285303
cirq.CNOT(q0, q1) ** 0.5, # Requires 2-qubit decomposition
304+
cirq.ControlledGate(cirq.Y)(q0, q1),
305+
cirq.ControlledGate(cirq.H)(q0, q1),
286306
cirq.SWAP(q0, q1),
287307
cirq.SWAP(q0, q1) ** 0.75, # Requires 2-qubit decomposition
288308
cirq.CCZ(q0, q1, q2),
@@ -356,15 +376,33 @@ def filter_unpredictable_numbers(text):
356376
creg m_multi[3];
357377
358378
379+
id q[0];
359380
z q[0];
360381
rz(pi*0.625) q[0];
382+
rz(0) q[0];
361383
y q[0];
362384
ry(pi*0.375) q[0];
385+
ry(0) q[0];
363386
x q[0];
364387
rx(pi*0.875) q[0];
365-
h q[1];
388+
rx(0) q[0];
389+
h q[0];
390+
id q[0];
366391
sx q[0];
367392
sxdg q[0];
393+
s q[0];
394+
sdg q[0];
395+
t q[0];
396+
tdg q[0];
397+
rx(pi*1.0) q[0];
398+
rx(pi*0.5) q[0];
399+
rx(pi*0.25) q[0];
400+
ry(pi*1.0) q[0];
401+
ry(pi*0.5) q[0];
402+
ry(pi*0.25) q[0];
403+
rz(pi*1.0) q[0];
404+
rz(pi*0.5) q[0];
405+
rz(pi*0.25) q[0];
368406
cz q[0],q[1];
369407
370408
// Gate: CZ**0.25
@@ -399,6 +437,8 @@ def filter_unpredictable_numbers(text):
399437
u3(pi*0.5,pi*0.5,pi*1.0) q[1];
400438
ry(pi*0.5) q[1];
401439
440+
cy q[0],q[1];
441+
ch q[0],q[1];
402442
swap q[0],q[1];
403443
404444
// Gate: SWAP**0.75

cirq/ops/common_gates.py

+33-13
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,13 @@ def _circuit_diagram_info_(
219219

220220
def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
221221
args.validate_version('2.0')
222-
if self._exponent == 1 and self._global_shift != -0.5:
223-
return args.format('x {0};\n', qubits[0])
224-
elif self._exponent == 0.5:
225-
return args.format('sx {0};\n', qubits[0])
226-
elif self._exponent == -0.5:
227-
return args.format('sxdg {0};\n', qubits[0])
222+
if self._global_shift == 0:
223+
if self._exponent == 1:
224+
return args.format('x {0};\n', qubits[0])
225+
elif self._exponent == 0.5:
226+
return args.format('sx {0};\n', qubits[0])
227+
elif self._exponent == -0.5:
228+
return args.format('sxdg {0};\n', qubits[0])
228229
return args.format('rx({0:half_turns}) {1};\n', self._exponent, qubits[0])
229230

230231
def _quil_(
@@ -308,6 +309,10 @@ def __str__(self) -> str:
308309
def __repr__(self) -> str:
309310
return f'cirq.Rx(rads={proper_repr(self._rads)})'
310311

312+
def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
313+
args.validate_version('2.0')
314+
return args.format('rx({0:half_turns}) {1};\n', self._exponent, qubits[0])
315+
311316
def _json_dict_(self) -> Dict[str, Any]:
312317
return {'rads': self._rads}
313318

@@ -480,6 +485,10 @@ def __str__(self) -> str:
480485
def __repr__(self) -> str:
481486
return f'cirq.Ry(rads={proper_repr(self._rads)})'
482487

488+
def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
489+
args.validate_version('2.0')
490+
return args.format('ry({0:half_turns}) {1};\n', self._exponent, qubits[0])
491+
483492
def _json_dict_(self) -> Dict[str, Any]:
484493
return {'rads': self._rads}
485494

@@ -654,13 +663,18 @@ def _circuit_diagram_info_(
654663

655664
def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
656665
args.validate_version('2.0')
657-
if self._exponent == 1 and self.global_shift != -0.5:
658-
return args.format('z {0};\n', qubits[0])
659-
elif self._exponent == 0.5:
660-
return args.format('s {0};\n', qubits[0])
661-
elif self._exponent == -0.5:
662-
return args.format('sdg {0};\n', qubits[0])
663666

667+
if self.global_shift == 0:
668+
if self._exponent == 1:
669+
return args.format('z {0};\n', qubits[0])
670+
elif self._exponent == 0.5:
671+
return args.format('s {0};\n', qubits[0])
672+
elif self._exponent == -0.5:
673+
return args.format('sdg {0};\n', qubits[0])
674+
elif self._exponent == 0.25:
675+
return args.format('t {0};\n', qubits[0])
676+
elif self._exponent == -0.25:
677+
return args.format('tdg {0};\n', qubits[0])
664678
return args.format('rz({0:half_turns}) {1};\n', self._exponent, qubits[0])
665679

666680
def _quil_(
@@ -756,6 +770,10 @@ def __str__(self) -> str:
756770
def __repr__(self) -> str:
757771
return f'cirq.Rz(rads={proper_repr(self._rads)})'
758772

773+
def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
774+
args.validate_version('2.0')
775+
return args.format('rz({0:half_turns}) {1};\n', self._exponent, qubits[0])
776+
759777
def _json_dict_(self) -> Dict[str, Any]:
760778
return {'rads': self._rads}
761779

@@ -860,7 +878,9 @@ def _circuit_diagram_info_(
860878

861879
def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
862880
args.validate_version('2.0')
863-
if self._exponent == 1:
881+
if self._exponent == 0:
882+
return args.format('id {0};\n', qubits[0])
883+
elif self._exponent == 1 and self._global_shift == 0:
864884
return args.format('h {0};\n', qubits[0])
865885

866886
return args.format(

cirq/ops/controlled_operation.py

+34-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@
3030
import numpy as np
3131

3232
from cirq import protocols, qis, value
33-
from cirq.ops import raw_types, gate_operation, controlled_gate, matrix_gates
33+
from cirq.ops import (
34+
controlled_gate,
35+
common_gates,
36+
eigen_gate,
37+
gate_operation,
38+
matrix_gates,
39+
raw_types,
40+
)
3441
from cirq.type_workarounds import NotImplementedType
3542

3643
if TYPE_CHECKING:
@@ -186,6 +193,32 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> np.ndarray:
186193
def _has_unitary_(self) -> bool:
187194
return protocols.has_unitary(self.sub_operation)
188195

196+
def _qasm_(self, args: 'cirq.QasmArgs') -> Optional[str]:
197+
if (
198+
hasattr(self._sub_operation, "gate")
199+
and len(self._controls) == 1
200+
and self._control_values == ((1,),)
201+
):
202+
gate = self.sub_operation.gate
203+
if (
204+
isinstance(gate, eigen_gate.EigenGate)
205+
and gate.exponent == 1
206+
and gate.global_shift == 0
207+
):
208+
instr = None
209+
if isinstance(gate, common_gates.XPowGate):
210+
instr = 'cx {0},{1};\n'
211+
elif isinstance(gate, common_gates.YPowGate):
212+
instr = 'cy {0},{1};\n'
213+
elif isinstance(gate, common_gates.ZPowGate):
214+
instr = 'cz {0},{1};\n'
215+
elif isinstance(gate, common_gates.HPowGate):
216+
instr = 'ch {0},{1};\n'
217+
if instr:
218+
return args.format(instr, self._controls[0], self.sub_operation.qubits[0])
219+
# Fallback to decompose.
220+
return None
221+
189222
def _extend_matrix(self, sub_matrix: np.ndarray) -> np.ndarray:
190223
qid_shape = protocols.qid_shape(self)
191224
sub_n = len(qid_shape) - len(self.controls)

0 commit comments

Comments
 (0)