def optimization_at(self, circuit: Circuit, index: int, op: Operation) -> Optional[PointOptimizationSummary]: if isinstance(op.gate, (MeasurementGate, SingleQubitGate, WaitGate)): new_op = op else: if op.gate is None: raise IncompatibleMomentError( f'Operation {op} has a missing gate') translated_gate = self._simulator.gates_translator(op.gate) if translated_gate is None: raise IncompatibleMomentError( f'Moment contains non-single qubit operation ' f'{op} with unsupported gate') a, b = op.qubits new_op = self._simulator.create_gate_with_drift( a, b, translated_gate).on(a, b) return PointOptimizationSummary(clear_span=1, clear_qubits=op.qubits, new_operations=new_op)
def _make_zeta_chi_gamma_compensation( circuit_with_calibration: CircuitWithCalibration, characterizations: List[PhasedFSimCalibrationResult], gates_translator: Callable[[Gate], Optional[PhaseCalibratedFSimGate]], permit_mixed_moments: bool, ) -> CircuitWithCalibration: if permit_mixed_moments: raise NotImplementedError( 'Mixed moments compensation ist supported yet') if len(circuit_with_calibration.circuit) != len( circuit_with_calibration.moment_to_calibration): raise ValueError('Moment allocations does not match circuit length') default_phases = PhasedFSimCharacterization(zeta=0.0, chi=0.0, gamma=0.0) compensated = Circuit() compensated_moment_to_calibration: List[Optional[int]] = [] for moment, characterization_index in zip( circuit_with_calibration.circuit, circuit_with_calibration.moment_to_calibration): parameters = None if characterization_index is not None: parameters = characterizations[characterization_index] decompositions: List[Tuple[Tuple[Operation, ...], ...]] = [] other: List[Operation] = [] new_moment_moment_to_calibration: Optional[List[Optional[int]]] = None for op in moment: if not isinstance(op, GateOperation): raise IncompatibleMomentError( 'Moment contains operation different than GateOperation') if isinstance(op.gate, _CALIBRATION_IRRELEVANT_GATES): other.append(op) continue a, b = op.qubits translated = gates_translator(op.gate) if translated is None: raise IncompatibleMomentError( f'Moment {moment} contains unsupported non-single qubit operation {op}' ) if parameters is None: raise ValueError( f'Missing characterization data for moment {moment}') pair_parameters = parameters.get_parameters(a, b) if pair_parameters is None: raise ValueError( f'Missing characterization data for pair {(a, b)} in {parameters}' ) pair_parameters = pair_parameters.merge_with(default_phases) corrections = FSimPhaseCorrections.from_characterization( (a, b), translated, pair_parameters, characterization_index, ) decompositions.append(corrections.operations) if new_moment_moment_to_calibration is None: new_moment_moment_to_calibration = corrections.moment_to_calibration else: assert ( new_moment_moment_to_calibration == corrections.moment_to_calibration ), f'Inconsistent decompositions with a moment {moment}' if other and decompositions: raise IncompatibleMomentError( f'Moment {moment} contains mixed operations') elif other: compensated += Moment(other) compensated_moment_to_calibration.append(characterization_index) elif decompositions: for operations in itertools.zip_longest(*decompositions, fillvalue=()): compensated += Moment(operations) assert new_moment_moment_to_calibration is not None # Required for mypy compensated_moment_to_calibration += new_moment_moment_to_calibration return CircuitWithCalibration(compensated, compensated_moment_to_calibration)
def _list_moment_pairs_to_characterize( moment: Moment, gates_translator: Callable[[Gate], Optional[PhaseCalibratedFSimGate]], canonicalize_pairs: bool, permit_mixed_moments: bool, ) -> Optional[Tuple[List[Tuple[Qid, Qid]], Gate]]: """Describes a given moment in terms of a Floquet characterization request. Args: moment: Moment to characterize. gates_translator: Function that translates a gate to a supported FSimGate which will undergo characterization. canonicalize_pairs: Whether to sort each of the qubit pair so that the first qubit is always lower than the second. permit_mixed_moments: Whether to allow a mix of two-qubit gates with other irrelevant single-qubit gates. Returns: Tuple with list of pairs to characterize and gate that should be used for characterization, or None when no gate to characterize exists in a given moment. Raises: IncompatibleMomentError when a moment contains operations other than the operations matched by gates_translator, or it mixes a single qubit and two qubit gates. """ other_operation = False gate: Optional[FSimGate] = None pairs = [] for op in moment: if not isinstance(op, GateOperation): raise IncompatibleMomentError( 'Moment contains operation different than GateOperation') if isinstance(op.gate, _CALIBRATION_IRRELEVANT_GATES): other_operation = True else: translated = gates_translator(op.gate) if translated is None: raise IncompatibleMomentError( f'Moment {moment} contains unsupported non-single qubit operation {op}' ) if gate is not None and gate != translated.engine_gate: raise IncompatibleMomentError( f'Moment {moment} contains operations resolved to two different gates {gate} ' f'and {translated.engine_gate}') else: gate = translated.engine_gate pair = cast( Tuple[Qid, Qid], tuple(sorted(op.qubits) if canonicalize_pairs else op.qubits)) pairs.append(pair) if gate is None: # Either empty, single-qubit or measurement moment. return None elif not permit_mixed_moments and other_operation: raise IncompatibleMomentError( f'Moment contains mixed two-qubit operations and either single-qubit measurement or ' f'wait operations.') return pairs, gate
def make_floquet_request_for_moment( moment: Moment, options: FloquetPhasedFSimCalibrationOptions, gates_translator: Callable[ [Gate], Optional[FSimGate]] = try_convert_sqrt_iswap_to_fsim, canonicalize_pairs: bool = False, sort_pairs: bool = False, ) -> Optional[FloquetPhasedFSimCalibrationRequest]: """Describes a given moment in terms of a Floquet characterization request. Args: moment: Moment to characterize. options: Options that are applied to each characterized gate within a moment. gates_translator: Function that translates a gate to a supported FSimGate which will undergo characterization. Defaults to sqrt_iswap_gates_translator. canonicalize_pairs: Whether to sort each of the qubit pair so that the first qubit is always lower than the second. sort_pairs: Whether to sort all the qutibt pairs extracted from the moment which will undergo characterization. Returns: Instance of FloquetPhasedFSimCalibrationRequest that characterizes a given moment, or None when it is an empty, measurement or single-qubit gates only moment. Raises: IncompatibleMomentError when a moment contains operations other than the operations matched by gates_translator, or it mixes a single qubit and two qubit gates. """ measurement = False single_qubit = False gate: Optional[FSimGate] = None pairs = [] for op in moment: if not isinstance(op, GateOperation): raise IncompatibleMomentError( 'Moment contains operation different than GateOperation') if isinstance(op.gate, MeasurementGate): measurement = True elif isinstance(op.gate, SingleQubitGate): single_qubit = True else: translated_gate = gates_translator(op.gate) if translated_gate is None: raise IncompatibleMomentError( f'Moment {moment} contains unsupported non-single qubit operation {op}' ) elif gate is not None and gate != translated_gate: raise IncompatibleMomentError( f'Moment {moment} contains operations resolved to two different gates {gate} ' f'and {translated_gate}') else: gate = translated_gate pair = cast( Tuple[Qid, Qid], tuple(sorted(op.qubits) if canonicalize_pairs else op.qubits)) pairs.append(pair) if gate is None: # Either empty, single-qubit or measurement moment. return None if gate is not None and (measurement or single_qubit): raise IncompatibleMomentError( f'Moment contains mixed two-qubit operations and ' f'single-qubit operations or measurement operations.') return FloquetPhasedFSimCalibrationRequest( pairs=tuple(sorted(pairs) if sort_pairs else pairs), gate=gate, options=options)
def zeta_chi_gamma_calibration_for_moments( circuit_with_calibration: CircuitWithCalibration, characterizations: List[PhasedFSimCalibrationResult], gates_translator: Callable[[Gate], Optional[FSimGate]] = try_convert_sqrt_iswap_to_fsim, ) -> CircuitWithCalibration: """Compensates circuit against errors in zeta, chi and gamma angles. This method creates a new circuit with a single-qubit Z gates added in a such way so that zeta, chi and gamma angles discovered by characterizations are cancelled-out and set to 0. This function preserves a moment structure of the circuit. All single qubit gates appear on new moments in the final circuit. Args: circuit_with_calibration: A CircuitWithCalibration (likely returned from run_calibrations) whose mapping argument corresponds to the results in the characterizations argument. characterizations: List of characterization results (likely returned from run_calibrations). This should correspond to the circuit and mapping in the circuit_with_calibration argument. gates_translator: Function that translates a gate to a supported FSimGate which will undergo characterization. Defaults to sqrt_iswap_gates_translator. Returns: Calibrated circuit together with its calibration metadata in CircuitWithCalibration object. The calibrated circuit has single-qubit Z gates added which compensates for the true gates imperfections. The moment to calibration mapping is updated for the new circuit so that successive calibrations could be applied. """ if len(circuit_with_calibration.circuit) != len(circuit_with_calibration.moment_to_calibration): raise ValueError('Moment allocations does not match circuit length') default_phases = PhasedFSimCharacterization(zeta=0.0, chi=0.0, gamma=0.0) compensated = Circuit() compensated_moment_to_calibration: List[Optional[int]] = [] for moment, characterization_index in zip( circuit_with_calibration.circuit, circuit_with_calibration.moment_to_calibration ): parameters = None if characterization_index is not None: parameters = characterizations[characterization_index] decompositions: List[Tuple[Tuple[Operation, ...], ...]] = [] other: List[Operation] = [] new_moment_moment_to_calibration: Optional[List[Optional[int]]] = None for op in moment: if not isinstance(op, GateOperation): raise IncompatibleMomentError( 'Moment contains operation different than GateOperation' ) if isinstance(op.gate, (MeasurementGate, SingleQubitGate)): other.append(op) continue a, b = op.qubits translated_gate = gates_translator(op.gate) if translated_gate is None: raise IncompatibleMomentError( f'Moment {moment} contains unsupported non-single qubit operation {op}' ) if parameters is None: raise ValueError(f'Missing characterization data for moment {moment}') pair_parameters = parameters.get_parameters(a, b) if pair_parameters is None: raise ValueError(f'Missing characterization data for pair {(a, b)} in {parameters}') pair_parameters = pair_parameters.merge_with(default_phases) corrections = FSimPhaseCorrections.from_characterization( (a, b), translated_gate, pair_parameters, characterization_index ) decompositions.append(corrections.operations) if new_moment_moment_to_calibration is None: new_moment_moment_to_calibration = corrections.moment_to_calibration else: assert ( new_moment_moment_to_calibration == corrections.moment_to_calibration ), f'Inconsistent decompositions with a moment {moment}' if other and decompositions: raise IncompatibleMomentError(f'Moment {moment} contains mixed operations') elif other: compensated += Moment(other) compensated_moment_to_calibration.append(characterization_index) elif decompositions: for operations in zip_longest(*decompositions, fillvalue=()): compensated += Moment(operations) assert new_moment_moment_to_calibration is not None # Required for mypy compensated_moment_to_calibration += new_moment_moment_to_calibration return CircuitWithCalibration(compensated, compensated_moment_to_calibration)