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
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
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