diff --git a/cirq-core/cirq/circuits/qasm_output_test.py b/cirq-core/cirq/circuits/qasm_output_test.py index 4264b65530d..fcfe0580e02 100644 --- a/cirq-core/cirq/circuits/qasm_output_test.py +++ b/cirq-core/cirq/circuits/qasm_output_test.py @@ -270,19 +270,39 @@ def __repr__(self): return 'DummyCompositeOperation()' return ( + cirq.I(q0), cirq.Z(q0), cirq.Z(q0) ** 0.625, + cirq.Z(q0) ** 0, cirq.Y(q0), cirq.Y(q0) ** 0.375, + cirq.Y(q0) ** 0, cirq.X(q0), cirq.X(q0) ** 0.875, - cirq.H(q1), + cirq.X(q0) ** 0, + cirq.H(q0), + cirq.H(q0) ** 0, cirq.X(q0) ** 0.5, cirq.X(q0) ** -0.5, + cirq.S(q0), + cirq.Z(q0) ** -0.5, + cirq.T(q0), + cirq.Z(q0) ** -0.25, + cirq.Rx(rads=np.pi)(q0), + cirq.Rx(rads=np.pi / 2)(q0), + cirq.Rx(rads=np.pi / 4)(q0), + cirq.Ry(rads=np.pi)(q0), + cirq.Ry(rads=np.pi / 2)(q0), + cirq.Ry(rads=np.pi / 4)(q0), + cirq.Rz(rads=np.pi)(q0), + cirq.Rz(rads=np.pi / 2)(q0), + cirq.Rz(rads=np.pi / 4)(q0), cirq.CZ(q0, q1), cirq.CZ(q0, q1) ** 0.25, # Requires 2-qubit decomposition cirq.CNOT(q0, q1), cirq.CNOT(q0, q1) ** 0.5, # Requires 2-qubit decomposition + cirq.ControlledGate(cirq.Y)(q0, q1), + cirq.ControlledGate(cirq.H)(q0, q1), cirq.SWAP(q0, q1), cirq.SWAP(q0, q1) ** 0.75, # Requires 2-qubit decomposition cirq.CCZ(q0, q1, q2), @@ -356,15 +376,33 @@ def filter_unpredictable_numbers(text): creg m_multi[3]; +id q[0]; z q[0]; rz(pi*0.625) q[0]; +rz(0) q[0]; y q[0]; ry(pi*0.375) q[0]; +ry(0) q[0]; x q[0]; rx(pi*0.875) q[0]; -h q[1]; +rx(0) q[0]; +h q[0]; +id q[0]; sx q[0]; sxdg q[0]; +s q[0]; +sdg q[0]; +t q[0]; +tdg q[0]; +rx(pi*1.0) q[0]; +rx(pi*0.5) q[0]; +rx(pi*0.25) q[0]; +ry(pi*1.0) q[0]; +ry(pi*0.5) q[0]; +ry(pi*0.25) q[0]; +rz(pi*1.0) q[0]; +rz(pi*0.5) q[0]; +rz(pi*0.25) q[0]; cz q[0],q[1]; // Gate: CZ**0.25 @@ -399,6 +437,8 @@ def filter_unpredictable_numbers(text): u3(pi*0.5,pi*0.5,pi*1.0) q[1]; ry(pi*0.5) q[1]; +cy q[0],q[1]; +ch q[0],q[1]; swap q[0],q[1]; // Gate: SWAP**0.75 diff --git a/cirq-core/cirq/ops/common_gates.py b/cirq-core/cirq/ops/common_gates.py index c846d16de2a..813d9e271af 100644 --- a/cirq-core/cirq/ops/common_gates.py +++ b/cirq-core/cirq/ops/common_gates.py @@ -219,12 +219,13 @@ def _circuit_diagram_info_( def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: args.validate_version('2.0') - if self._exponent == 1 and self._global_shift != -0.5: - return args.format('x {0};\n', qubits[0]) - elif self._exponent == 0.5: - return args.format('sx {0};\n', qubits[0]) - elif self._exponent == -0.5: - return args.format('sxdg {0};\n', qubits[0]) + if self._global_shift == 0: + if self._exponent == 1: + return args.format('x {0};\n', qubits[0]) + elif self._exponent == 0.5: + return args.format('sx {0};\n', qubits[0]) + elif self._exponent == -0.5: + return args.format('sxdg {0};\n', qubits[0]) return args.format('rx({0:half_turns}) {1};\n', self._exponent, qubits[0]) def _quil_( @@ -308,6 +309,10 @@ def __str__(self) -> str: def __repr__(self) -> str: return f'cirq.Rx(rads={proper_repr(self._rads)})' + def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: + args.validate_version('2.0') + return args.format('rx({0:half_turns}) {1};\n', self._exponent, qubits[0]) + def _json_dict_(self) -> Dict[str, Any]: return {'rads': self._rads} @@ -480,6 +485,10 @@ def __str__(self) -> str: def __repr__(self) -> str: return f'cirq.Ry(rads={proper_repr(self._rads)})' + def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: + args.validate_version('2.0') + return args.format('ry({0:half_turns}) {1};\n', self._exponent, qubits[0]) + def _json_dict_(self) -> Dict[str, Any]: return {'rads': self._rads} @@ -654,13 +663,18 @@ def _circuit_diagram_info_( def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: args.validate_version('2.0') - if self._exponent == 1 and self.global_shift != -0.5: - return args.format('z {0};\n', qubits[0]) - elif self._exponent == 0.5: - return args.format('s {0};\n', qubits[0]) - elif self._exponent == -0.5: - return args.format('sdg {0};\n', qubits[0]) + if self.global_shift == 0: + if self._exponent == 1: + return args.format('z {0};\n', qubits[0]) + elif self._exponent == 0.5: + return args.format('s {0};\n', qubits[0]) + elif self._exponent == -0.5: + return args.format('sdg {0};\n', qubits[0]) + elif self._exponent == 0.25: + return args.format('t {0};\n', qubits[0]) + elif self._exponent == -0.25: + return args.format('tdg {0};\n', qubits[0]) return args.format('rz({0:half_turns}) {1};\n', self._exponent, qubits[0]) def _quil_( @@ -756,6 +770,10 @@ def __str__(self) -> str: def __repr__(self) -> str: return f'cirq.Rz(rads={proper_repr(self._rads)})' + def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: + args.validate_version('2.0') + return args.format('rz({0:half_turns}) {1};\n', self._exponent, qubits[0]) + def _json_dict_(self) -> Dict[str, Any]: return {'rads': self._rads} @@ -860,7 +878,9 @@ def _circuit_diagram_info_( def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: args.validate_version('2.0') - if self._exponent == 1: + if self._exponent == 0: + return args.format('id {0};\n', qubits[0]) + elif self._exponent == 1 and self._global_shift == 0: return args.format('h {0};\n', qubits[0]) return args.format( diff --git a/cirq-core/cirq/ops/controlled_operation.py b/cirq-core/cirq/ops/controlled_operation.py index ac4a15691a7..33a78df0150 100644 --- a/cirq-core/cirq/ops/controlled_operation.py +++ b/cirq-core/cirq/ops/controlled_operation.py @@ -30,7 +30,14 @@ import numpy as np from cirq import protocols, qis, value -from cirq.ops import raw_types, gate_operation, controlled_gate, matrix_gates +from cirq.ops import ( + controlled_gate, + common_gates, + eigen_gate, + gate_operation, + matrix_gates, + raw_types, +) from cirq.type_workarounds import NotImplementedType if TYPE_CHECKING: @@ -186,6 +193,32 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> np.ndarray: def _has_unitary_(self) -> bool: return protocols.has_unitary(self.sub_operation) + def _qasm_(self, args: 'cirq.QasmArgs') -> Optional[str]: + if ( + hasattr(self._sub_operation, "gate") + and len(self._controls) == 1 + and self._control_values == ((1,),) + ): + gate = self.sub_operation.gate + if ( + isinstance(gate, eigen_gate.EigenGate) + and gate.exponent == 1 + and gate.global_shift == 0 + ): + instr = None + if isinstance(gate, common_gates.XPowGate): + instr = 'cx {0},{1};\n' + elif isinstance(gate, common_gates.YPowGate): + instr = 'cy {0},{1};\n' + elif isinstance(gate, common_gates.ZPowGate): + instr = 'cz {0},{1};\n' + elif isinstance(gate, common_gates.HPowGate): + instr = 'ch {0},{1};\n' + if instr: + return args.format(instr, self._controls[0], self.sub_operation.qubits[0]) + # Fallback to decompose. + return None + def _extend_matrix(self, sub_matrix: np.ndarray) -> np.ndarray: qid_shape = protocols.qid_shape(self) sub_n = len(qid_shape) - len(self.controls)