def _translate_two_qubit_cirq_operation_to_braket_instruction( op: "cirq.Operation", ) -> List[Instruction]: """Translates a two-qubit Cirq operation to a (sequence of) Braket instruction(s) according to the following rules: 1. Attempts to find a "standard translation" from Cirq to Braket. - e.g., checks if `op` is a CNOT and, if so, returns the Braket CNOT. 2. If (1) is not successful, performs a KAK decomposition of the unitary of `op` to obtain a circuit ──A1──X^0.5───@───X^a───X──────────────────@───B1─── │ │ │ ──A2──────────X───Y^b───@───X^-0.5───Z^c───X───B2──── where A1, A2, B1, and B2 are arbitrary single-qubit unitaries and a, b, c are floats. Args: op: Two-qubit Cirq operation to translate. """ # Translate qubit indices. q1, q2 = [qubit.x for qubit in op.qubits] # Check common two-qubit gates. if isinstance(op.gate, cirq_ops.CNotPowGate) and np.isclose( abs(op.gate.exponent), 1.0): return [Instruction(braket_gates.CNot(), [q1, q2])] elif isinstance(op.gate, cirq_ops.CZPowGate) and np.isclose( abs(op.gate.exponent), 1.0): return [Instruction(braket_gates.CZ(), [q1, q2])] elif isinstance(op.gate, cirq_ops.ISwapPowGate) and np.isclose( op.gate.exponent, 1.0): return [Instruction(braket_gates.ISwap(), [q1, q2])] elif isinstance(op.gate, cirq_ops.XXPowGate): return [ Instruction(braket_gates.XX(op.gate.exponent * np.pi), [q1, q2]) ] elif isinstance(op.gate, cirq_ops.YYPowGate): return [ Instruction(braket_gates.YY(op.gate.exponent * np.pi), [q1, q2]) ] elif isinstance(op.gate, cirq_ops.ZZPowGate): return [ Instruction(braket_gates.ZZ(op.gate.exponent * np.pi), [q1, q2]) ] # Arbitrary two-qubit unitary decomposition. kak = kak_decomposition(protocols.unitary(op)) A1, A2 = kak.single_qubit_operations_before x, y, z = kak.interaction_coefficients a = x * -2 / np.pi + 0.5 b = y * -2 / np.pi + 0.5 c = z * -2 / np.pi + 0.5 B1, B2 = kak.single_qubit_operations_after return [ *_translate_one_qubit_cirq_operation_to_braket_instruction(A1, q1), *_translate_one_qubit_cirq_operation_to_braket_instruction(A2, q2), Instruction(braket_gates.Rx(0.5 * np.pi), q1), Instruction(braket_gates.CNot(), [q1, q2]), Instruction(braket_gates.Rx(a * np.pi), q1), Instruction(braket_gates.Ry(b * np.pi), q2), Instruction(braket_gates.CNot(), [q2, q1]), Instruction(braket_gates.Rx(-0.5 * np.pi), q2), Instruction(braket_gates.Rz(c * np.pi), q2), Instruction(braket_gates.CNot(), [q1, q2]), *_translate_one_qubit_cirq_operation_to_braket_instruction(B1, q1), *_translate_one_qubit_cirq_operation_to_braket_instruction(B2, q2), ]
def _translate_one_qubit_cirq_operation_to_braket_instruction( op: Union[np.ndarray, "cirq.Operation"], target: Optional[int] = None, ) -> List[Instruction]: """Translates a one-qubit Cirq operation to a (sequence of) Braket instruction(s) according to the following rules: 1. Attempts to find a "standard translation" from Cirq to Braket. - e.g., checks if `op` is Pauli-X and, if so, returns the Braket X. 2. If (1) is not successful, decomposes the unitary of `op` to Rz(theta) Ry(phi) Rz(lambda) and returns the series of rotations as Braket instructions. Args: op: One-qubit Cirq operation to translate. target: Qubit index for the op to act on. Must be specified and if only if `op` is given as a numpy array. """ # Translate qubit index. if not isinstance(op, np.ndarray): target = op.qubits[0].x if target is None: raise ValueError( "Arg `target` must be specified when `op` is a matrix.") # Check common single-qubit gates. if isinstance(op, cirq_ops.Operation): if isinstance(op.gate, cirq_ops.XPowGate): exponent = op.gate.exponent if np.isclose(exponent, 1.0) or np.isclose(exponent, -1.0): return [Instruction(braket_gates.X(), target)] elif np.isclose(exponent, 0.5): return [Instruction(braket_gates.V(), target)] elif np.isclose(exponent, -0.5): return [Instruction(braket_gates.Vi(), target)] return [Instruction(braket_gates.Rx(exponent * np.pi), target)] elif isinstance(op.gate, cirq_ops.YPowGate): exponent = op.gate.exponent if np.isclose(exponent, 1.0) or np.isclose(exponent, -1.0): return [Instruction(braket_gates.Y(), target)] return [Instruction(braket_gates.Ry(exponent * np.pi), target)] elif isinstance(op.gate, cirq_ops.ZPowGate): exponent = op.gate.exponent if np.isclose(exponent, 1.0) or np.isclose(exponent, -1.0): return [Instruction(braket_gates.Z(), target)] elif np.isclose(exponent, 0.5): return [Instruction(braket_gates.S(), target)] elif np.isclose(exponent, -0.5): return [Instruction(braket_gates.Si(), target)] elif np.isclose(exponent, 0.25): return [Instruction(braket_gates.T(), target)] elif np.isclose(exponent, -0.25): return [Instruction(braket_gates.Ti(), target)] return [Instruction(braket_gates.Rz(exponent * np.pi), target)] elif isinstance(op.gate, cirq_ops.HPowGate) and np.isclose( abs(op.gate.exponent), 1.0): return [Instruction(braket_gates.H(), target)] # Arbitrary single-qubit unitary decomposition. # TODO: This does not account for global phase. if isinstance(op, cirq_ops.Operation): unitary_matrix = protocols.unitary(op) else: unitary_matrix = op a, b, c = deconstruct_single_qubit_matrix_into_angles(unitary_matrix) return [ Instruction(braket_gates.Rz(a), target), Instruction(braket_gates.Ry(b), target), Instruction(braket_gates.Rz(c), target), ]
# "cz": gates.CZ, # # "ch": CHGate, # # "crx": CRXGate, # # "cry": CRYGate, # # "crz": CRZGate, # # "cu1": CU1Gate, # # "cu3": CU3Gate, # "ccx": gates.CCNot, # "cswap": gates.CSwap # } # TODO: look into a possibility to use device's native gates set (no the IBMQ natives!) # First element is executed first! _qiskit_2_braket_conversion = { "u1": lambda lam: [gates.Rz(lam)], "u2": lambda phi, lam: [gates.Rz(lam), gates.Ry(numpy.pi/2), gates.Rz(phi)], "u3": lambda theta, phi, lam: [gates.Rz(lam), gates.Rx(numpy.pi/2), gates.Rz(theta), gates.Rx(-numpy.pi/2), gates.Rz(phi)], "cx": lambda: [gates.CNot()] } def convert_experiment(experiment: QasmQobjExperiment) -> Circuit: qc = Circuit() qasm_obj_instruction: QasmQobjInstruction for qasm_obj_instruction in experiment.instructions: name = qasm_obj_instruction.name
def _(ry: qml.RY, parameters): phi = parameters[0] return gates.Ry(-phi) if ry.inverse else gates.Ry(phi)
"circuit,expected_unitary", [ (Circuit().h(0), gates.H().to_matrix()), (Circuit().h(0).add_result_type( ResultType.Probability(target=[0])), gates.H().to_matrix()), (Circuit().x(0), gates.X().to_matrix()), (Circuit().y(0), gates.Y().to_matrix()), (Circuit().z(0), gates.Z().to_matrix()), (Circuit().s(0), gates.S().to_matrix()), (Circuit().si(0), gates.Si().to_matrix()), (Circuit().t(0), gates.T().to_matrix()), (Circuit().ti(0), gates.Ti().to_matrix()), (Circuit().v(0), gates.V().to_matrix()), (Circuit().vi(0), gates.Vi().to_matrix()), (Circuit().rx(0, 0.15), gates.Rx(0.15).to_matrix()), (Circuit().ry(0, 0.15), gates.Ry(0.15).to_matrix()), (Circuit().rz(0, 0.15), gates.Rz(0.15).to_matrix()), (Circuit().phaseshift(0, 0.15), gates.PhaseShift(0.15).to_matrix()), (Circuit().cnot(1, 0), gates.CNot().to_matrix()), (Circuit().cnot(1, 0).add_result_type( ResultType.StateVector()), gates.CNot().to_matrix()), (Circuit().swap(1, 0), gates.Swap().to_matrix()), (Circuit().swap(0, 1), gates.Swap().to_matrix()), (Circuit().iswap(1, 0), gates.ISwap().to_matrix()), (Circuit().iswap(0, 1), gates.ISwap().to_matrix()), (Circuit().pswap(1, 0, 0.15), gates.PSwap(0.15).to_matrix()), (Circuit().pswap(0, 1, 0.15), gates.PSwap(0.15).to_matrix()), (Circuit().xy(1, 0, 0.15), gates.XY(0.15).to_matrix()), (Circuit().xy(0, 1, 0.15), gates.XY(0.15).to_matrix()), (Circuit().cphaseshift(1, 0, 0.15), gates.CPhaseShift(0.15).to_matrix()),