Exemplo n.º 1
0
def controlled_op_to_operations(control: ops.QubitId,
                                target: ops.QubitId,
                                operation: np.ndarray,
                                tolerance: float = 0.0) -> List[ops.Operation]:
    """Decomposes a controlled single-qubit operation into Z/XY/CZ gates.

    Args:
        control: The control qubit.
        target: The qubit to apply an operation to, when the control is on.
        operation: The single-qubit operation being controlled.
        tolerance: A limit on the amount of error introduced by the
            construction.

    Returns:
        A list of Operations that apply the controlled operation.
    """
    u, z_phase, global_phase = single_qubit_op_to_framed_phase_form(operation)
    if abs(z_phase - 1) <= tolerance:
        return []

    u_gates = single_qubit_matrix_to_gates(u, tolerance)
    if u_gates and isinstance(u_gates[-1], ops.RotZGate):
        # Don't keep border operations that commute with CZ.
        del u_gates[-1]

    ops_before = [gate(target) for gate in u_gates]
    ops_after = ops.inverse(ops_before)
    effect = ops.CZ(control, target)**(cmath.phase(z_phase) / math.pi)
    kickback = ops.Z(control)**(cmath.phase(global_phase) / math.pi)

    return list(
        ops.flatten_op_tree(
            (ops_before, effect,
             kickback if abs(global_phase - 1) > tolerance else [],
             ops_after)))
Exemplo n.º 2
0
 def default_decompose(self) -> ops.OP_TREE:
     if len(self.pauli_string) <= 0:
         return
     qubits = self.qubits
     any_qubit = qubits[0]
     to_z_ops = ops.freeze_op_tree(self.pauli_string.to_z_basis_ops())
     xor_decomp = tuple(xor_nonlocal_decompose(qubits, any_qubit))
     yield to_z_ops
     yield xor_decomp
     if isinstance(self.half_turns, value.Symbol):
         if self.pauli_string.negated:
             yield ops.X(any_qubit)
         yield ops.RotZGate(half_turns=self.half_turns)(any_qubit)
         if self.pauli_string.negated:
             yield ops.X(any_qubit)
     else:
         half_turns = self.half_turns * (-1 if self.pauli_string.negated
                                         else 1)
         yield ops.Z(any_qubit)**half_turns
     yield ops.inverse(xor_decomp)
     yield ops.inverse(to_z_ops)
Exemplo n.º 3
0
 def default_decompose(self) -> ops.OP_TREE:
     if len(self.pauli_string) <= 0:
         return
     qubits = self.qubits
     any_qubit = qubits[0]
     to_z_ops = ops.freeze_op_tree(self.pauli_string.to_z_basis_ops())
     xor_decomp = tuple(xor_nonlocal_decompose(qubits, any_qubit))
     yield to_z_ops
     yield xor_decomp
     if isinstance(self.half_turns, value.Symbol):
         if self.pauli_string.negated:
             yield ops.X(any_qubit)
         yield ops.RotZGate(half_turns=self.half_turns)(any_qubit)
         if self.pauli_string.negated:
             yield ops.X(any_qubit)
     else:
         half_turns = self.half_turns * (-1 if self.pauli_string.negated
                                            else 1)
         yield ops.Z(any_qubit) ** half_turns
     yield ops.inverse(xor_decomp)
     yield ops.inverse(to_z_ops)
Exemplo n.º 4
0
def verify_decomposition_inverse(*op_tree, max_test_value=2**100, depth=1):
    qubits = set()
    op_list = tuple(ops.flatten_op_tree(op_tree))
    for op in op_list:
        qubits.update(op.qubits)
    qubits = sorted(qubits)
    num_qubits = len(qubits)
    sub_ops = tuple(ops.flatten_op_tree(decompose_depth(op_list, d=depth)))
    sub_ops_inv = tuple(ops.flatten_op_tree(decompose_depth(ops.inverse(op_list), d=depth)))

    for trits in itertools.product((0,1,2), repeat=num_qubits):
        state = trit_list_to_state(qubits, trits)
        state_orig = state.copy()
        for op in sub_ops:
            op.apply_to_ternary_state(state)
        for op in sub_ops_inv:
            op.apply_to_ternary_state(state)
        if state != state_orig:
            input_state_str = ''.join(map(str, trits))
            output_state_str = ''.join(map(str, (state[q] for q in qubits)))
            raise RuntimeError(
                'Gate {!r} inverse is invalid for input {} != {}'.format(
                op_list, input_state_str, output_state_str))
Exemplo n.º 5
0
def controlled_op_to_operations(
        control: ops.QubitId,
        target: ops.QubitId,
        operation: np.ndarray,
        tolerance: float = 0.0) -> List[ops.Operation]:
    """Decomposes a controlled single-qubit operation into Z/XY/CZ gates.

    Args:
        control: The control qubit.
        target: The qubit to apply an operation to, when the control is on.
        operation: The single-qubit operation being controlled.
        tolerance: A limit on the amount of error introduced by the
            construction.

    Returns:
        A list of Operations that apply the controlled operation.
    """
    u, z_phase, global_phase = single_qubit_op_to_framed_phase_form(operation)
    if abs(z_phase - 1) <= tolerance:
        return []

    u_gates = single_qubit_matrix_to_gates(u, tolerance)
    if u_gates and isinstance(u_gates[-1], ops.RotZGate):
        # Don't keep border operations that commute with CZ.
        del u_gates[-1]

    ops_before = [gate(target) for gate in u_gates]
    ops_after = ops.inverse(ops_before)
    effect = ops.CZ(control, target) ** (cmath.phase(z_phase) / math.pi)
    kickback = ops.Z(control) ** (cmath.phase(global_phase) / math.pi)

    return list(ops.flatten_op_tree((
        ops_before,
        effect,
        kickback if abs(global_phase - 1) > tolerance else [],
        ops_after)))