def ms(rads: float) -> ops.XXPowGate: """The Mølmer–Sørensen gate, a native two-qubit operation in ion traps. A rotation around the XX axis in the two-qubit bloch sphere. The gate implements the following unitary: exp(-i t XX) = [ cos(t) 0 0 -isin(t)] [ 0 cos(t) -isin(t) 0 ] [ 0 -isin(t) cos(t) 0 ] [-isin(t) 0 0 cos(t) ] Args: rads: The rotation angle in radians. Returns: Mølmer–Sørensen gate rotating by the desired amount. """ return ops.XXPowGate(exponent=rads * 2 / np.pi, global_shift=-0.5)
def _translate_two_qubit_braket_instruction_to_cirq_operation( instr: Instruction, ) -> List["cirq.Operation"]: """Converts the two-qubit braket instruction to Cirq. Args: instr: Two-qubit Braket instruction to convert. Raises: ValueError: If the instruction cannot be converted to Cirq. """ qubits = [LineQubit(int(qubit)) for qubit in instr.target] gate = instr.operator # Two-qubit non-parameterized gates. if isinstance(gate, braket_gates.CNot): return [cirq_ops.CNOT.on(*qubits)] elif isinstance(gate, braket_gates.Swap): return [cirq_ops.SWAP.on(*qubits)] elif isinstance(gate, braket_gates.ISwap): return [cirq_ops.ISWAP.on(*qubits)] elif isinstance(gate, braket_gates.CZ): return [cirq_ops.CZ.on(*qubits)] elif isinstance(gate, braket_gates.CY): return [ cirq_ops.S.on(qubits[1])**-1, cirq_ops.CNOT.on(*qubits), cirq_ops.S.on(qubits[1]), ] # Two-qubit parameterized gates. elif isinstance(gate, braket_gates.PSwap): raise ValueError # TODO. elif isinstance(gate, braket_gates.CPhaseShift): return [cirq_ops.CZ.on(*qubits)**(gate.angle / np.pi)] elif isinstance(gate, braket_gates.CPhaseShift00): raise ValueError # TODO. elif isinstance(gate, braket_gates.CPhaseShift01): raise ValueError # TODO. elif isinstance(gate, braket_gates.CPhaseShift10): raise ValueError # TODO. elif isinstance(gate, braket_gates.XX): return [ cirq_ops.XXPowGate(exponent=gate.angle / np.pi, global_shift=-0.5).on(*qubits) ] elif isinstance(gate, braket_gates.YY): return [ cirq_ops.YYPowGate(exponent=gate.angle / np.pi, global_shift=-0.5).on(*qubits) ] elif isinstance(gate, braket_gates.ZZ): return [ cirq_ops.ZZPowGate(exponent=gate.angle / np.pi, global_shift=-0.5).on(*qubits) ] elif isinstance(gate, braket_gates.XY): return [cirq_ops.ISwapPowGate(exponent=gate.angle / np.pi).on(*qubits)] else: raise ValueError( f"Unable to convert the instruction {instr} to Cirq. If you think " "this is a bug, you can open an issue on the Mitiq GitHub at " "https://github.com/unitaryfund/mitiq.")
cirq_circuit = Circuit(uncommon_gate.on(LineQubit(0))) test_circuit = from_braket(to_braket(cirq_circuit)) testing.assert_allclose_up_to_global_phase( protocols.unitary(test_circuit), protocols.unitary(cirq_circuit), atol=1e-7, ) @pytest.mark.parametrize( "common_gate", [ ops.CNOT, ops.CZ, ops.ISWAP, ops.XXPowGate(exponent=-0.2), ops.YYPowGate(exponent=0.3), ops.ZZPowGate(exponent=-0.1), ], ) def test_to_from_braket_common_two_qubit_gates(common_gate): """These gates should stay the same (i.e., not get decomposed) when converting Cirq -> Braket -> Cirq. """ cirq_circuit = Circuit(common_gate.on(*LineQubit.range(2))) test_circuit = from_braket(to_braket(cirq_circuit)) testing.assert_allclose_up_to_global_phase( protocols.unitary(test_circuit), protocols.unitary(cirq_circuit), atol=1e-7, )
def _translate_two_qubit_braket_instruction_to_cirq_operation( instr: Instruction, ) -> List["cirq.Operation"]: """Converts the two-qubit braket instruction to Cirq. Args: instr: Two-qubit Braket instruction to convert. Raises: ValueError: If the instruction cannot be converted to Cirq. """ qubits = [LineQubit(int(qubit)) for qubit in instr.target] gate = instr.operator # Two-qubit non-parameterized gates. if isinstance(gate, braket_gates.CNot): return [cirq_ops.CNOT.on(*qubits)] elif isinstance(gate, braket_gates.Swap): return [cirq_ops.SWAP.on(*qubits)] elif isinstance(gate, braket_gates.ISwap): return [cirq_ops.ISWAP.on(*qubits)] elif isinstance(gate, braket_gates.CZ): return [cirq_ops.CZ.on(*qubits)] elif isinstance(gate, braket_gates.CY): return [ cirq_ops.S.on(qubits[1]) ** -1, cirq_ops.CNOT.on(*qubits), cirq_ops.S.on(qubits[1]), ] # Two-qubit parameterized gates. elif isinstance(gate, braket_gates.CPhaseShift): return [cirq_ops.CZ.on(*qubits) ** (gate.angle / np.pi)] elif isinstance(gate, braket_gates.CPhaseShift00): return [ cirq_ops.XX(*qubits), cirq_ops.CZ.on(*qubits) ** (gate.angle / np.pi), cirq_ops.XX(*qubits), ] elif isinstance(gate, braket_gates.CPhaseShift01): return [ cirq_ops.X(qubits[0]), cirq_ops.CZ.on(*qubits) ** (gate.angle / np.pi), cirq_ops.X(qubits[0]), ] elif isinstance(gate, braket_gates.CPhaseShift10): return [ cirq_ops.X(qubits[1]), cirq_ops.CZ.on(*qubits) ** (gate.angle / np.pi), cirq_ops.X(qubits[1]), ] elif isinstance(gate, braket_gates.PSwap): return [ cirq_ops.SWAP.on(*qubits), cirq_ops.CNOT.on(*qubits), cirq_ops.Z.on(qubits[1]) ** (gate.angle / np.pi), cirq_ops.CNOT.on(*qubits), ] elif isinstance(gate, braket_gates.XX): return [ cirq_ops.XXPowGate( exponent=gate.angle / np.pi, global_shift=-0.5 ).on(*qubits) ] elif isinstance(gate, braket_gates.YY): return [ cirq_ops.YYPowGate( exponent=gate.angle / np.pi, global_shift=-0.5 ).on(*qubits) ] elif isinstance(gate, braket_gates.ZZ): return [ cirq_ops.ZZPowGate( exponent=gate.angle / np.pi, global_shift=-0.5 ).on(*qubits) ] elif isinstance(gate, braket_gates.XY): return [cirq_ops.ISwapPowGate(exponent=gate.angle / np.pi).on(*qubits)] else: _raise_braket_to_cirq_error(instr)