Example #1
0
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
Example #2
0
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
Example #3
0
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))
Example #4
0
    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)
Example #5
0
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)
Example #6
0
 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)
Example #7
0
    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))