def decompose_arbitrary_into_syc_tabulation(qubit_a: ops.Qid, qubit_b: ops.Qid, op: ops.GateOperation, tabulation: GateTabulation): """Synthesize an arbitrary 2 qubit operation to a sycamore operation using the given Tabulation. Args: qubit_a: first qubit of the operation qubit_b: second qubit of the operation op: operation to decompose tabulation: A tabulation for the Sycamore gate. Returns: New operations iterable object """ new_ops = [] result = tabulation.compile_two_qubit_gate(protocols.unitary(op)) local_gates = result.local_unitaries for i, gate_pairs in enumerate(local_gates): new_ops.extend([ term.on(qubit_a) for term in optimizers.single_qubit_matrix_to_gates(gate_pairs[0]) ]) new_ops.extend([ term.on(qubit_b) for term in optimizers.single_qubit_matrix_to_gates(gate_pairs[1]) ]) if i != len(local_gates) - 1: new_ops.append(google.SYC.on(qubit_a, qubit_b)) return new_ops
def decompose_arbitrary_into_syc_analytic(qubit_a: ops.Qid, qubit_b: ops.Qid, op: ops.GateOperation): """Synthesize an arbitrary 2 qubit operation to a sycamore operation using the given Tabulation. Args: qubit_a: first qubit of the operation qubit_b: second qubit of the operation op: operation to decompose tabulation: A tabulation for the Sycamore gate. Returns: New operations iterable object """ new_ops = optimizers.two_qubit_matrix_to_operations(op.qubits[0], op.qubits[1], op, allow_partial_czs=True) gate_ops = [] for new_op in new_ops: num_qubits = len(new_op.qubits) if num_qubits == 1: gate_ops.extend([ term.on(new_op.qubits[0]) for term in optimizers.single_qubit_matrix_to_gates( protocols.unitary(new_op)) ]) elif num_qubits == 2: gate_ops.extend( ops.flatten_to_ops( known_two_q_operations_to_sycamore_operations( new_op.qubits[0], new_op.qubits[1], cast(ops.GateOperation, new_op)))) return gate_ops
def create_corrected_circuit(target_unitary: np.ndarray, program: circuits.Circuit, q0: ops.Qid, q1: ops.Qid): # Get the local equivalents b_0, b_1, a_0, a_1 = find_local_equivalents( target_unitary, program.unitary(qubit_order=ops.QubitOrder.explicit([q0, q1]))) # Apply initial corrections yield (gate(q0) for gate in optimizers.single_qubit_matrix_to_gates(b_0)) yield (gate(q1) for gate in optimizers.single_qubit_matrix_to_gates(b_1)) # Apply interaction part yield program # Apply final corrections yield (gate(q0) for gate in optimizers.single_qubit_matrix_to_gates(a_0)) yield (gate(q1) for gate in optimizers.single_qubit_matrix_to_gates(a_1))
def _decompose_two_qubit(self, operation: 'cirq.Operation') -> ops.OP_TREE: """Decomposes a two qubit gate into XXPow, YYPow, and ZZPow plus single qubit gates.""" mat = protocols.unitary(operation) kak = linalg.kak_decomposition(mat, check_preconditions=False) for qubit, mat in zip(operation.qubits, kak.single_qubit_operations_before): gates = optimizers.single_qubit_matrix_to_gates(mat, self.atol) for gate in gates: yield gate(qubit) two_qubit_gates = [parity_gates.XX, parity_gates.YY, parity_gates.ZZ] for two_qubit_gate, coefficient in zip(two_qubit_gates, kak.interaction_coefficients): yield (two_qubit_gate**(-coefficient * 2 / np.pi))(*operation.qubits) for qubit, mat in zip(operation.qubits, kak.single_qubit_operations_after): for gate in optimizers.single_qubit_matrix_to_gates( mat, self.atol): yield gate(qubit)
def _do_single_on(u: np.ndarray, q: 'cirq.Qid', atol: float = 1e-8): for gate in optimizers.single_qubit_matrix_to_gates(u, atol): yield gate(q)
def _decompose_single_qubit(self, operation: 'cirq.Operation') -> ops.OP_TREE: qubit = operation.qubits[0] mat = protocols.unitary(operation) for gate in optimizers.single_qubit_matrix_to_gates(mat, self.atol): yield gate(qubit)
def known_two_q_operations_to_sycamore_operations( self, qubit_a: ops.Qid, qubit_b: ops.Qid, op: ops.GateOperation) -> ops.OP_TREE: """ Synthesize a known gate operation to a sycamore operation This function dispatches based on gate type Args: qubit_a: first qubit of GateOperation qubit_b: second qubit of GateOperation op: operation to decompose Returns: New operations iterable object """ gate = op.gate if isinstance(gate, ops.CNotPowGate): return [ ops.Y(qubit_b)**-0.5, cphase( cast(ops.CNotPowGate, gate).exponent * np.pi, qubit_a, qubit_b), ops.Y(qubit_b)**0.5, ] elif isinstance(gate, ops.CZPowGate): gate = cast(ops.CZPowGate, gate) if math.isclose(gate.exponent, 1.0): # check if CZ or CPHASE return decompose_cz_into_syc(qubit_a, qubit_b) else: # because CZPowGate == diag([1, 1, 1, e^{i pi phi}]) return cphase(gate.exponent * np.pi, qubit_a, qubit_b) elif isinstance(gate, ops.SwapPowGate) and math.isclose( cast(ops.SwapPowGate, gate).exponent, 1.0): return decompose_swap_into_syc(qubit_a, qubit_b) elif isinstance(gate, ops.ISwapPowGate) and math.isclose( cast(ops.ISwapPowGate, gate).exponent, 1.0): return decompose_iswap_into_syc(qubit_a, qubit_b) elif isinstance(gate, ops.ZZPowGate): return rzz( cast(ops.ZZPowGate, gate).exponent * np.pi / 2, *op.qubits) elif isinstance(gate, ops.MatrixGate) and len(op.qubits) == 2: new_ops = optimizers.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], op, allow_partial_czs=True) gate_ops = [] for new_op in new_ops: num_qubits = len(new_op.qubits) if num_qubits == 1: gate_ops.extend([ term.on(new_op.qubits[0]) for term in optimizers.single_qubit_matrix_to_gates( protocols.unitary(new_op)) ]) elif num_qubits == 2: gate_ops.extend( ops.flatten_to_ops( self.known_two_q_operations_to_sycamore_operations( new_op.qubits[0], new_op.qubits[1], cast(ops.GateOperation, new_op)))) return gate_ops else: raise ValueError("Unrecognized gate: {!r}".format(op))