Ejemplo n.º 1
0
def _max_weight_observable(observables: Iterable[ops.PauliString]) \
        -> Union[None, ops.PauliString]:
    """Create a new observable that is compatible with all input observables
    and has the maximum non-identity elements.

    The returned PauliString is constructed by taking the non-identity
    single-qubit Pauli at each qubit position.

    This function will return `None` if the input observables do not share a
    tensor product basis.

    For example, the _max_weight_observable of ["XI", "IZ"] is "XZ". Asking for
    the max weight observable of something like ["XI", "ZI"] will return None.

    The returned value need not actually be present in the input observables.
    Coefficients from input observables will be dropped.
    """
    qubit_pauli_map = dict()  # type: Dict[ops.Qid, ops.Pauli]
    for observable in observables:
        for qubit, pauli in observable.items():
            if qubit in qubit_pauli_map:
                if qubit_pauli_map[qubit] != pauli:
                    return None
            else:
                qubit_pauli_map[qubit] = pauli
    return ops.PauliString(qubit_pauli_map)
def _setting_to_z_observable(setting: InitObsSetting):
    qubits = setting.observable.qubits
    return InitObsSetting(
        init_state=zeros_state(qubits),
        observable=ops.PauliString(qubit_pauli_map={q: ops.Z
                                                    for q in qubits}),
    )
def calibrate_readout_error(
    qubits: Iterable[ops.Qid],
    sampler: Union['cirq.Simulator', 'cirq.Sampler'],
    stopping_criteria: StoppingCriteria,
):
    # We know there won't be any fancy sweeps or observables so we can
    # get away with more repetitions per job
    stopping_criteria = dataclasses.replace(stopping_criteria,
                                            repetitions_per_chunk=100_000)

    # Simultaneous readout characterization:
    # We can measure all qubits simultaneously (i.e. _max_setting is ZZZ..ZZ
    # for all qubits). We will extract individual qubit quantities, so there
    # are `n_qubits` InitObsSetting, each responsible for one <Z>.
    #
    # Readout symmetrization means we just need to measure the "identity"
    # circuit. In reality, this corresponds to measuring I for half the time
    # and X for the other half.
    init_state = zeros_state(qubits)
    max_setting = InitObsSetting(init_state=init_state,
                                 observable=ops.PauliString(
                                     {q: ops.Z
                                      for q in qubits}))
    grouped_settings = {
        max_setting: [
            InitObsSetting(init_state=init_state,
                           observable=ops.PauliString({q: ops.Z}))
            for q in qubits
        ]
    }

    results = measure_grouped_settings(
        circuit=circuits.Circuit(),
        grouped_settings=grouped_settings,
        sampler=sampler,
        stopping_criteria=stopping_criteria,
        circuit_sweep=study.UnitSweep,
        readout_symmetrization=True,
    )
    (result, ) = list(results)
    return result
 def _matrix_to_pauli_string_phasors(self, mat: np.ndarray,
                                     qubit: 'cirq.Qid') -> ops.OP_TREE:
     rotations = optimizers.single_qubit_matrix_to_pauli_rotations(
         mat, self.atol)
     out_ops: List[ops.Operation] = []
     for pauli, half_turns in rotations:
         if self.keep_clifford and linalg.all_near_zero_mod(
                 half_turns, 0.5):
             cliff_gate = ops.SingleQubitCliffordGate.from_quarter_turns(
                 pauli, round(half_turns * 2))
             if out_ops and not isinstance(out_ops[-1],
                                           ops.PauliStringPhasor):
                 op = cast(ops.GateOperation, out_ops[-1])
                 gate = cast(ops.SingleQubitCliffordGate, op.gate)
                 out_ops[-1] = gate.merged_with(cliff_gate)(qubit)
             else:
                 out_ops.append(cliff_gate(qubit))
         else:
             out_ops.append(
                 ops.PauliStringPhasor(ops.PauliString(pauli.on(qubit)),
                                       exponent_neg=round(half_turns, 10)))
     return out_ops
Ejemplo n.º 5
0
    def try_merge_clifford(cliff_op: ops.GateOperation, start_i: int) -> bool:
        (orig_qubit, ) = cliff_op.qubits
        remaining_cliff_gate = ops.SingleQubitCliffordGate.I
        for pauli, quarter_turns in reversed(
                cast(ops.SingleQubitCliffordGate,
                     cliff_op.gate).decompose_rotation()):
            trans = remaining_cliff_gate.transform(pauli)
            pauli = trans.to
            quarter_turns *= -1 if trans.flip else 1
            string_op = ops.PauliStringPhasor(ops.PauliString(
                pauli(cliff_op.qubits[0])),
                                              exponent_neg=quarter_turns / 2)

            merge_i, merge_op, num_passed = find_merge_point(
                start_i, string_op, quarter_turns == 2)
            assert merge_i > start_i
            assert len(merge_op.pauli_string) == 1, 'PauliString length != 1'

            qubit, pauli = next(iter(merge_op.pauli_string.items()))
            quarter_turns = round(merge_op.exponent_relative * 2)
            quarter_turns *= int(merge_op.pauli_string.coefficient.real)
            quarter_turns %= 4
            part_cliff_gate = ops.SingleQubitCliffordGate.from_quarter_turns(
                pauli, quarter_turns)

            other_op = all_ops[merge_i] if merge_i < len(all_ops) else None
            if other_op is not None and qubit not in set(other_op.qubits):
                other_op = None

            if isinstance(other_op, ops.GateOperation) and isinstance(
                    other_op.gate, ops.SingleQubitCliffordGate):
                # Merge with another SingleQubitCliffordGate
                new_op = part_cliff_gate.merged_with(other_op.gate)(qubit)
                all_ops[merge_i] = new_op
            elif (isinstance(other_op, ops.GateOperation)
                  and isinstance(other_op.gate, ops.CZPowGate)
                  and other_op.gate.exponent == 1 and quarter_turns == 2):
                # Pass whole Pauli gate over CZ, possibly adding a Z gate
                if pauli != ops.pauli_gates.Z:
                    other_qubit = other_op.qubits[other_op.qubits.index(qubit)
                                                  - 1]
                    all_ops.insert(merge_i + 1,
                                   ops.SingleQubitCliffordGate.Z(other_qubit))
                all_ops.insert(merge_i + 1, part_cliff_gate(qubit))
            elif isinstance(other_op, ops.PauliStringPhasor):
                # Pass over a non-Clifford gate
                mod_op = other_op.pass_operations_over(
                    [part_cliff_gate(qubit)])
                all_ops[merge_i] = mod_op
                all_ops.insert(merge_i + 1, part_cliff_gate(qubit))
            elif merge_i > start_i + 1 and num_passed > 0:
                # Moved Clifford through the circuit but nothing to merge
                all_ops.insert(merge_i, part_cliff_gate(qubit))
            else:
                # Couldn't move Clifford
                remaining_cliff_gate = remaining_cliff_gate.merged_with(
                    part_cliff_gate)

        if remaining_cliff_gate == ops.SingleQubitCliffordGate.I:
            all_ops.pop(start_i)
            return True
        all_ops[start_i] = remaining_cliff_gate(orig_qubit)
        return False
Ejemplo n.º 6
0
    def try_merge_clifford(cliff_op: ops.GateOperation, start_i: int) -> bool:
        orig_qubit, = cliff_op.qubits
        remaining_cliff_gate = ops.SingleQubitCliffordGate.I
        for pauli, quarter_turns in reversed(
                cast(ops.SingleQubitCliffordGate,
                     cliff_op.gate).decompose_rotation()):
            trans = remaining_cliff_gate.transform(pauli)
            pauli = trans.to
            quarter_turns *= -1 if trans.flip else 1
            string_op = ops.PauliStringPhasor(ops.PauliString(
                pauli(cliff_op.qubits[0])),
                                              exponent_neg=quarter_turns / 2)

            merge_i, merge_op, num_passed = find_merge_point(
                start_i, string_op, quarter_turns == 2)
            assert merge_i > start_i
            assert len(merge_op.pauli_string) == 1, 'PauliString length != 1'

            qubit, pauli = next(iter(merge_op.pauli_string.items()))
            quarter_turns = round(merge_op.exponent_relative * 2)
            if merge_op.pauli_string.coefficient not in [1, -1]:
                # TODO: Add support for more general phases.
                # Github issue: https://github.com/quantumlib/Cirq/issues/2962
                # Legacy coverage ignore, we need test code that hits this.
                # coverage: ignore
                raise NotImplementedError(
                    'Only +1/-1 pauli string coefficients currently supported')
            quarter_turns *= int(merge_op.pauli_string.coefficient.real)
            quarter_turns %= 4
            part_cliff_gate = ops.SingleQubitCliffordGate.from_quarter_turns(
                pauli, quarter_turns)

            other_op = all_ops[merge_i] if merge_i < len(all_ops) else None
            if other_op is not None and qubit not in set(other_op.qubits):
                other_op = None

            if (isinstance(other_op, ops.GateOperation) and isinstance(
                    other_op.gate, ops.SingleQubitCliffordGate)):
                # Merge with another SingleQubitCliffordGate
                new_op = part_cliff_gate.merged_with(other_op.gate)(qubit)
                all_ops[merge_i] = new_op
            elif (isinstance(other_op, ops.GateOperation)
                  and isinstance(other_op.gate, ops.CZPowGate)
                  and other_op.gate.exponent == 1 and quarter_turns == 2):
                # Pass whole Pauli gate over CZ, possibly adding a Z gate
                if pauli != ops.pauli_gates.Z:
                    other_qubit = other_op.qubits[other_op.qubits.index(qubit)
                                                  - 1]
                    all_ops.insert(merge_i + 1,
                                   ops.SingleQubitCliffordGate.Z(other_qubit))
                all_ops.insert(merge_i + 1, part_cliff_gate(qubit))
            elif isinstance(other_op, ops.PauliStringPhasor):
                # Pass over a non-Clifford gate
                mod_op = other_op.pass_operations_over(
                    [part_cliff_gate(qubit)])
                all_ops[merge_i] = mod_op
                all_ops.insert(merge_i + 1, part_cliff_gate(qubit))
            elif merge_i > start_i + 1 and num_passed > 0:
                # Moved Clifford through the circuit but nothing to merge
                all_ops.insert(merge_i, part_cliff_gate(qubit))
            else:
                # Couldn't move Clifford
                remaining_cliff_gate = remaining_cliff_gate.merged_with(
                    part_cliff_gate)

        if remaining_cliff_gate == ops.SingleQubitCliffordGate.I:
            all_ops.pop(start_i)
            return True
        all_ops[start_i] = remaining_cliff_gate(orig_qubit)
        return False