def test_get_parameters(): q_00, q_01, q_02, q_03 = [cirq.GridQubit(0, index) for index in range(4)] gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) result = PhasedFSimCalibrationResult( parameters={ (q_00, q_01): PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=None, gamma=None, phi=0.3), (q_02, q_03): PhasedFSimCharacterization(theta=0.4, zeta=0.5, chi=None, gamma=None, phi=0.6), }, gate=gate, options=FloquetPhasedFSimCalibrationOptions( characterize_theta=True, characterize_zeta=True, characterize_chi=False, characterize_gamma=False, characterize_phi=True, ), ) assert result.get_parameters(q_00, q_01) == PhasedFSimCharacterization( theta=0.1, zeta=0.2, chi=None, gamma=None, phi=0.3) assert result.get_parameters(q_01, q_00) == PhasedFSimCharacterization( theta=0.1, zeta=-0.2, chi=None, gamma=None, phi=0.3) assert result.get_parameters(q_02, q_03) == PhasedFSimCharacterization( theta=0.4, zeta=0.5, chi=None, gamma=None, phi=0.6) assert result.get_parameters(q_00, q_03) is None
def test_result_override(): q_00, q_01, q_02, q_03 = [cirq.GridQubit(0, index) for index in range(4)] gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) options = WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION result = PhasedFSimCalibrationResult( parameters={ (q_00, q_01): PhasedFSimCharacterization( theta=0.1, zeta=0.2, chi=None, gamma=0.4, phi=0.5 ), (q_02, q_03): PhasedFSimCharacterization( theta=0.6, zeta=0.7, chi=None, gamma=0.9, phi=1.0 ), }, gate=gate, options=options, ) overridden = result.override(options.zeta_chi_gamma_correction_override()) assert overridden == PhasedFSimCalibrationResult( parameters={ (q_00, q_01): PhasedFSimCharacterization( theta=0.1, zeta=0.0, chi=None, gamma=0.0, phi=0.5 ), (q_02, q_03): PhasedFSimCharacterization( theta=0.6, zeta=0.0, chi=None, gamma=0.0, phi=1.0 ), }, gate=gate, options=WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION, )
def test_any_none(): characterization_angles = {'theta': 0.1, 'zeta': 0.2, 'chi': 0.3, 'gamma': 0.4, 'phi': 0.5} assert not PhasedFSimCharacterization(**characterization_angles).any_none() for angle in characterization_angles: none_angles = dict(characterization_angles) del none_angles[angle] assert PhasedFSimCharacterization(**none_angles).any_none()
def test_asdict(): characterization_angles = { 'theta': 0.1, 'zeta': 0.2, 'chi': 0.3, 'gamma': 0.4, 'phi': 0.5 } characterization = PhasedFSimCharacterization(**characterization_angles) assert characterization.asdict() == characterization_angles
def test_parameters_for_qubits_swapped(): characterization = PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=0.3, gamma=0.4, phi=0.5) assert characterization.parameters_for_qubits_swapped( ) == PhasedFSimCharacterization(theta=0.1, zeta=-0.2, chi=-0.3, gamma=0.4, phi=0.5)
def test_all_none(): assert PhasedFSimCharacterization().all_none() characterization_angles = { 'theta': 0.1, 'zeta': 0.2, 'chi': 0.3, 'gamma': 0.4, 'phi': 0.5 } for angle, value in characterization_angles.items(): assert not PhasedFSimCharacterization(**{angle: value}).all_none()
def test_options_phase_corrected_override(): assert (ALL_ANGLES_FLOQUET_PHASED_FSIM_CHARACTERIZATION. zeta_chi_gamma_correction_override() == PhasedFSimCharacterization( zeta=0.0, chi=0.0, gamma=0.0)) assert (FloquetPhasedFSimCalibrationOptions( characterize_theta=False, characterize_zeta=False, characterize_chi=False, characterize_gamma=False, characterize_phi=False, ).zeta_chi_gamma_correction_override() == PhasedFSimCharacterization())
def test_phase_calibrated_fsim_gate_compensated(phase_exponent: float): a, b = cirq.LineQubit.range(2) ideal_gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) characterized_gate = cirq.PhasedFSimGate(theta=ideal_gate.theta, zeta=0.1, chi=0.2, gamma=0.3, phi=ideal_gate.phi) parameters = PhasedFSimCharacterization( theta=ideal_gate.theta, zeta=characterized_gate.zeta, chi=characterized_gate.chi, gamma=characterized_gate.gamma, phi=ideal_gate.phi, ) calibrated = PhaseCalibratedFSimGate(ideal_gate, phase_exponent=phase_exponent) # Passing characterized_gate as engine_gate simulates the hardware execution. operations = calibrated.with_zeta_chi_gamma_compensated( (a, b), parameters, engine_gate=characterized_gate) cirq.testing.assert_allclose_up_to_global_phase( cirq.unitary(cirq.Circuit(operations)), cirq.unitary( cirq.Circuit([ [cirq.Z(a)**-phase_exponent, cirq.Z(b)**phase_exponent], ideal_gate.on(a, b), [cirq.Z(a)**phase_exponent, cirq.Z(b)**-phase_exponent], ])), atol=1e-8, )
def test_phase_calibrated_fsim_gate_as_characterized_phased_fsim_gate( phase_exponent: float): a, b = cirq.LineQubit.range(2) ideal_gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) characterized_gate = cirq.PhasedFSimGate(theta=ideal_gate.theta, zeta=0.1, chi=0.2, gamma=0.3, phi=ideal_gate.phi) parameters = PhasedFSimCharacterization( theta=ideal_gate.theta, zeta=characterized_gate.zeta, chi=characterized_gate.chi, gamma=characterized_gate.gamma, phi=ideal_gate.phi, ) calibrated = PhaseCalibratedFSimGate(ideal_gate, phase_exponent=phase_exponent) phased_gate = calibrated.as_characterized_phased_fsim_gate(parameters).on( a, b) assert np.allclose( cirq.unitary(phased_gate), cirq.unitary( cirq.Circuit([ [cirq.Z(a)**-phase_exponent, cirq.Z(b)**phase_exponent], characterized_gate.on(a, b), [cirq.Z(a)**phase_exponent, cirq.Z(b)**-phase_exponent], ])), )
def test_run_characterization_with_simulator(): q_00, q_01, q_02, q_03 = [cirq.GridQubit(0, index) for index in range(4)] gate = SQRT_ISWAP_GATE request = FloquetPhasedFSimCalibrationRequest( gate=gate, pairs=((q_00, q_01), (q_02, q_03)), options=FloquetPhasedFSimCalibrationOptions( characterize_theta=True, characterize_zeta=True, characterize_chi=False, characterize_gamma=False, characterize_phi=True, ), ) simulator = PhasedFSimEngineSimulator.create_with_ideal_sqrt_iswap() actual = workflow.run_characterizations([request], simulator) assert actual == [ PhasedFSimCalibrationResult( parameters={ (q_00, q_01): PhasedFSimCharacterization(theta=np.pi / 4, zeta=0.0, chi=None, gamma=None, phi=0.0), (q_02, q_03): PhasedFSimCharacterization(theta=np.pi / 4, zeta=0.0, chi=None, gamma=None, phi=0.0), }, gate=SQRT_ISWAP_GATE, options=FloquetPhasedFSimCalibrationOptions( characterize_theta=True, characterize_zeta=True, characterize_chi=False, characterize_gamma=False, characterize_phi=True, ), ) ]
def sample_gate(a: Qid, b: Qid, gate: FSimGate) -> PhasedFSimCharacterization: assert isinstance(gate, FSimGate), f'Expected FSimGate, got {gate}' assert np.isclose(gate.theta, np.pi / 4) and np.isclose( gate.phi, 0.0), f'Expected ISWAP ** -0.5 like gate, got {gate}' if (a, b) in parameters: pair_parameters = parameters[(a, b)] if not isinstance(pair_parameters, PhasedFSimCharacterization): pair_parameters = PhasedFSimCharacterization( **pair_parameters) elif (b, a) in parameters: pair_parameters = parameters[(b, a)] if not isinstance(pair_parameters, PhasedFSimCharacterization): pair_parameters = PhasedFSimCharacterization( **pair_parameters) pair_parameters = pair_parameters.parameters_for_qubits_swapped( ) elif ideal_when_missing_gate: pair_parameters = SQRT_ISWAP_PARAMETERS else: raise ValueError(f'Missing parameters for pair {(a, b)}') if pair_parameters.any_none(): if not ideal_when_missing_parameter: raise ValueError( f'Missing parameter value for pair {(a, b)}, ' f'parameters={pair_parameters}') pair_parameters = pair_parameters.merge_with( SQRT_ISWAP_PARAMETERS) return pair_parameters
def sample_gate(_1: Qid, _2: Qid, gate: FSimGate) -> PhasedFSimCharacterization: assert isinstance(gate, FSimGate), f'Expected FSimGate, got {gate}' assert np.isclose(gate.theta, np.pi / 4) and np.isclose( gate.phi, 0.0), f'Expected ISWAP ** -0.5 like gate, got {gate}' return PhasedFSimCharacterization(theta=np.pi / 4, zeta=0.0, chi=0.0, gamma=0.0, phi=0.0)
def test_merge_matching_results(): q_00, q_01, q_02, q_03 = [cirq.GridQubit(0, index) for index in range(4)] gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) options = WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION parameters_1 = { (q_00, q_01): PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=None, gamma=None, phi=0.3), } parameters_2 = { (q_02, q_03): PhasedFSimCharacterization(theta=0.4, zeta=0.5, chi=None, gamma=None, phi=0.6), } results = [ PhasedFSimCalibrationResult( parameters=parameters_1, gate=gate, options=options, ), PhasedFSimCalibrationResult( parameters=parameters_2, gate=gate, options=options, ), ] assert merge_matching_results(results) == PhasedFSimCalibrationResult( parameters={ **parameters_1, **parameters_2 }, gate=gate, options=options, )
def sample_gate(_1: Qid, _2: Qid, gate: FSimGate) -> PhasedFSimCharacterization: assert isinstance(gate, FSimGate), f'Expected FSimGate, got {gate}' assert np.isclose(gate.theta, np.pi / 4) and np.isclose( gate.phi, 0.0), f'Expected ISWAP ** -0.5 like gate, got {gate}' return PhasedFSimCharacterization( theta=sample_value(mean.theta, sigma.theta), zeta=sample_value(mean.zeta, sigma.zeta), chi=sample_value(mean.chi, sigma.chi), gamma=sample_value(mean.gamma, sigma.gamma), phi=sample_value(mean.phi, sigma.phi), )
def get_calibrations( self, requests: Sequence[PhasedFSimCalibrationRequest] ) -> List[PhasedFSimCalibrationResult]: """Retrieves the calibration that matches the requests Args: requests: Calibration requests to obtain. Returns: Calibration results that reflect the internal state of simulator. """ results = [] for request in requests: if isinstance(request, FloquetPhasedFSimCalibrationRequest): options = request.options characterize_theta = options.characterize_theta characterize_zeta = options.characterize_zeta characterize_chi = options.characterize_chi characterize_gamma = options.characterize_gamma characterize_phi = options.characterize_phi else: raise ValueError(f'Unsupported calibration request {request}') translated = self.gates_translator(request.gate) if translated is None: raise ValueError( f'Calibration request contains unsupported gate {request.gate}' ) parameters = {} for a, b in request.pairs: drifted = self.create_gate_with_drift(a, b, translated) parameters[a, b] = PhasedFSimCharacterization( theta=drifted.theta if characterize_theta else None, zeta=drifted.zeta if characterize_zeta else None, chi=drifted.chi if characterize_chi else None, gamma=drifted.gamma if characterize_gamma else None, phi=drifted.phi if characterize_phi else None, ) results.append( PhasedFSimCalibrationResult(parameters=parameters, gate=request.gate, options=options)) return results
def test_run_characterization(): q_00, q_01, q_02, q_03 = [cirq.GridQubit(0, index) for index in range(4)] gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) request = FloquetPhasedFSimCalibrationRequest( gate=gate, pairs=((q_00, q_01), (q_02, q_03)), options=FloquetPhasedFSimCalibrationOptions( characterize_theta=True, characterize_zeta=True, characterize_chi=False, characterize_gamma=False, characterize_phi=True, ), ) result = cirq.google.CalibrationResult( code=cirq.google.api.v2.calibration_pb2.SUCCESS, error_message=None, token=None, valid_until=None, metrics=cirq.google.Calibration( cirq.google.api.v2.metrics_pb2.MetricsSnapshot(metrics=[ cirq.google.api.v2.metrics_pb2.Metric( name='angles', targets=[ '0_qubit_a', '0_qubit_b', '0_theta_est', '0_zeta_est', '0_phi_est', '1_qubit_a', '1_qubit_b', '1_theta_est', '1_zeta_est', '1_phi_est', ], values=[ cirq.google.api.v2.metrics_pb2.Value(str_val='0_0'), cirq.google.api.v2.metrics_pb2.Value(str_val='0_1'), cirq.google.api.v2.metrics_pb2.Value(double_val=0.1), cirq.google.api.v2.metrics_pb2.Value(double_val=0.2), cirq.google.api.v2.metrics_pb2.Value(double_val=0.3), cirq.google.api.v2.metrics_pb2.Value(str_val='0_2'), cirq.google.api.v2.metrics_pb2.Value(str_val='0_3'), cirq.google.api.v2.metrics_pb2.Value(double_val=0.4), cirq.google.api.v2.metrics_pb2.Value(double_val=0.5), cirq.google.api.v2.metrics_pb2.Value(double_val=0.6), ], ) ])), ) job = cirq.google.engine.EngineJob('', '', '', None) job._calibration_results = [result] engine = mock.MagicMock(spec=cirq.google.Engine) engine.run_calibration.return_value = job progress_calls = [] def progress(step: int, steps: int) -> None: progress_calls.append((step, steps)) actual = workflow.run_characterizations([request], engine, 'qproc', cirq.google.FSIM_GATESET, progress_func=progress) expected = [ PhasedFSimCalibrationResult( parameters={ (q_00, q_01): PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=None, gamma=None, phi=0.3), (q_02, q_03): PhasedFSimCharacterization(theta=0.4, zeta=0.5, chi=None, gamma=None, phi=0.6), }, gate=gate, options=FloquetPhasedFSimCalibrationOptions( characterize_theta=True, characterize_zeta=True, characterize_chi=False, characterize_gamma=False, characterize_phi=True, ), ) ] assert actual == expected assert progress_calls == [(1, 1)]
def test_floquet_parse_result(): q_00, q_01, q_02, q_03 = [cirq.GridQubit(0, index) for index in range(4)] gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) request = FloquetPhasedFSimCalibrationRequest( gate=gate, pairs=((q_00, q_01), (q_02, q_03)), options=FloquetPhasedFSimCalibrationOptions( characterize_theta=True, characterize_zeta=True, characterize_chi=False, characterize_gamma=False, characterize_phi=True, ), ) result = cirq.google.CalibrationResult( code=cirq.google.api.v2.calibration_pb2.SUCCESS, error_message=None, token=None, valid_until=None, metrics=cirq.google.Calibration( cirq.google.api.v2.metrics_pb2.MetricsSnapshot(metrics=[ cirq.google.api.v2.metrics_pb2.Metric( name='angles', targets=[ '0_qubit_a', '0_qubit_b', '0_theta_est', '0_zeta_est', '0_phi_est', '1_qubit_a', '1_qubit_b', '1_theta_est', '1_zeta_est', '1_phi_est', ], values=[ cirq.google.api.v2.metrics_pb2.Value(str_val='0_0'), cirq.google.api.v2.metrics_pb2.Value(str_val='0_1'), cirq.google.api.v2.metrics_pb2.Value(double_val=0.1), cirq.google.api.v2.metrics_pb2.Value(double_val=0.2), cirq.google.api.v2.metrics_pb2.Value(double_val=0.3), cirq.google.api.v2.metrics_pb2.Value(str_val='0_2'), cirq.google.api.v2.metrics_pb2.Value(str_val='0_3'), cirq.google.api.v2.metrics_pb2.Value(double_val=0.4), cirq.google.api.v2.metrics_pb2.Value(double_val=0.5), cirq.google.api.v2.metrics_pb2.Value(double_val=0.6), ], ) ])), ) assert request.parse_result(result) == PhasedFSimCalibrationResult( parameters={ (q_00, q_01): PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=None, gamma=None, phi=0.3), (q_02, q_03): PhasedFSimCharacterization(theta=0.4, zeta=0.5, chi=None, gamma=None, phi=0.6), }, gate=gate, options=FloquetPhasedFSimCalibrationOptions( characterize_theta=True, characterize_zeta=True, characterize_chi=False, characterize_gamma=False, characterize_phi=True, ), )
def test_merge_matching_results_when_incompatible_fails(): q_00, q_01, q_02, q_03 = [cirq.GridQubit(0, index) for index in range(4)] gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) options = WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION parameters_1 = { (q_00, q_01): PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=None, gamma=None, phi=0.3), } parameters_2 = { (q_02, q_03): PhasedFSimCharacterization(theta=0.4, zeta=0.5, chi=None, gamma=None, phi=0.6), } with pytest.raises(ValueError): results = [ PhasedFSimCalibrationResult( parameters=parameters_1, gate=gate, options=options, ), PhasedFSimCalibrationResult( parameters=parameters_1, gate=gate, options=options, ), ] assert merge_matching_results(results) with pytest.raises(ValueError): results = [ PhasedFSimCalibrationResult( parameters=parameters_1, gate=gate, options=options, ), PhasedFSimCalibrationResult( parameters=parameters_2, gate=cirq.CZ, options=options, ), ] assert merge_matching_results(results) with pytest.raises(ValueError): results = [ PhasedFSimCalibrationResult( parameters=parameters_1, gate=gate, options=options, ), PhasedFSimCalibrationResult( parameters=parameters_2, gate=gate, options=ALL_ANGLES_FLOQUET_PHASED_FSIM_CHARACTERIZATION, ), ] assert merge_matching_results(results)
def test_run_floquet_characterization_for_circuit(): q_00, q_01, q_02, q_03 = [cirq.GridQubit(0, index) for index in range(4)] gate = cirq.FSimGate(theta=np.pi / 4, phi=0.0) circuit = cirq.Circuit([gate.on(q_00, q_01), gate.on(q_02, q_03)]) options = FloquetPhasedFSimCalibrationOptions( characterize_theta=True, characterize_zeta=True, characterize_chi=False, characterize_gamma=False, characterize_phi=True, ) job = cirq.google.engine.EngineJob('', '', '', None) job._calibration_results = [ cirq.google.CalibrationResult( code=cirq.google.api.v2.calibration_pb2.SUCCESS, error_message=None, token=None, valid_until=None, metrics=cirq.google.Calibration( cirq.google.api.v2.metrics_pb2.MetricsSnapshot(metrics=[ cirq.google.api.v2.metrics_pb2.Metric( name='angles', targets=[ '0_qubit_a', '0_qubit_b', '0_theta_est', '0_zeta_est', '0_phi_est', '1_qubit_a', '1_qubit_b', '1_theta_est', '1_zeta_est', '1_phi_est', ], values=[ cirq.google.api.v2.metrics_pb2.Value( str_val='0_0'), cirq.google.api.v2.metrics_pb2.Value( str_val='0_1'), cirq.google.api.v2.metrics_pb2.Value( double_val=0.1), cirq.google.api.v2.metrics_pb2.Value( double_val=0.2), cirq.google.api.v2.metrics_pb2.Value( double_val=0.3), cirq.google.api.v2.metrics_pb2.Value( str_val='0_2'), cirq.google.api.v2.metrics_pb2.Value( str_val='0_3'), cirq.google.api.v2.metrics_pb2.Value( double_val=0.4), cirq.google.api.v2.metrics_pb2.Value( double_val=0.5), cirq.google.api.v2.metrics_pb2.Value( double_val=0.6), ], ) ])), ) ] engine = mock.MagicMock(spec=cirq.google.Engine) engine.run_calibration.return_value = job circuit_with_calibration, requests = workflow.run_floquet_characterization_for_circuit( circuit, engine, 'qproc', cirq.google.FSIM_GATESET, options=options) assert requests == [ PhasedFSimCalibrationResult( parameters={ (q_00, q_01): PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=None, gamma=None, phi=0.3), (q_02, q_03): PhasedFSimCharacterization(theta=0.4, zeta=0.5, chi=None, gamma=None, phi=0.6), }, gate=gate, options=options, ) ] assert circuit_with_calibration.circuit == circuit assert circuit_with_calibration.moment_to_calibration == [0]
def test_merge_with(): characterization = PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=0.3) other = PhasedFSimCharacterization(gamma=0.4, phi=0.5, theta=0.6) assert characterization.merge_with(other) == PhasedFSimCharacterization( theta=0.1, zeta=0.2, chi=0.3, gamma=0.4, phi=0.5)
def create_with_random_gaussian_sqrt_iswap( cls, mean: PhasedFSimCharacterization = SQRT_ISWAP_PARAMETERS, *, simulator: Optional[Simulator] = None, sigma: PhasedFSimCharacterization = PhasedFSimCharacterization( theta=0.02, zeta=0.05, chi=0.05, gamma=0.05, phi=0.02), random_or_seed: RANDOM_STATE_OR_SEED_LIKE = None, ) -> 'PhasedFSimEngineSimulator': """Creates a PhasedFSimEngineSimulator that introduces a random deviation from the mean. The random deviations are described by a Gaussian distribution of a given mean and sigma, for each angle respectively. Each gate for each pair of qubits retains the sampled values for the entire simulation, even when used multiple times within a circuit. Attributes: mean: The mean value for each unitary angle. All parameters must be provided. simulator: Simulator object to use. When None, a new instance of cirq.Simulator() will be created. sigma: The standard deviation for each unitary angle. For sigma parameters that are None, the mean value will be used without any sampling. Returns: New PhasedFSimEngineSimulator instance. """ if mean.any_none(): raise ValueError( f'All mean values must be provided, got mean of {mean}') rand = parse_random_state(random_or_seed) def sample_value(gaussian_mean: Optional[float], gaussian_sigma: Optional[float]) -> float: assert gaussian_mean is not None if gaussian_sigma is None: return gaussian_mean return rand.normal(gaussian_mean, gaussian_sigma) def sample_gate(_1: Qid, _2: Qid, gate: FSimGate) -> PhasedFSimCharacterization: assert isinstance(gate, FSimGate), f'Expected FSimGate, got {gate}' assert np.isclose(gate.theta, np.pi / 4) and np.isclose( gate.phi, 0.0), f'Expected ISWAP ** -0.5 like gate, got {gate}' return PhasedFSimCharacterization( theta=sample_value(mean.theta, sigma.theta), zeta=sample_value(mean.zeta, sigma.zeta), chi=sample_value(mean.chi, sigma.chi), gamma=sample_value(mean.gamma, sigma.gamma), phi=sample_value(mean.phi, sigma.phi), ) if simulator is None: simulator = Simulator() return cls(simulator, drift_generator=sample_gate, gates_translator=try_convert_sqrt_iswap_to_fsim)
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 test_zeta_chi_gamma_calibration_for_moments_invalid_argument_fails( ) -> None: a, b, c = cirq.LineQubit.range(3) with pytest.raises(ValueError): circuit_with_calibration = workflow.CircuitWithCalibration( cirq.Circuit(), [1]) workflow.zeta_chi_gamma_calibration_for_moments( circuit_with_calibration, []) with pytest.raises(ValueError): circuit_with_calibration = workflow.CircuitWithCalibration( cirq.Circuit(SQRT_ISWAP_GATE.on(a, b)), [None]) workflow.zeta_chi_gamma_calibration_for_moments( circuit_with_calibration, []) with pytest.raises(ValueError): circuit_with_calibration = workflow.CircuitWithCalibration( cirq.Circuit(SQRT_ISWAP_GATE.on(a, b)), [0]) characterizations = [ PhasedFSimCalibrationResult( parameters={}, gate=SQRT_ISWAP_GATE, options=WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION, ) ] workflow.zeta_chi_gamma_calibration_for_moments( circuit_with_calibration, characterizations) with pytest.raises(workflow.IncompatibleMomentError): circuit_with_calibration = workflow.CircuitWithCalibration( cirq.Circuit(cirq.GlobalPhaseOperation(coefficient=1.0)), [None]) workflow.zeta_chi_gamma_calibration_for_moments( circuit_with_calibration, []) with pytest.raises(workflow.IncompatibleMomentError): circuit_with_calibration = workflow.CircuitWithCalibration( cirq.Circuit(cirq.CZ.on(a, b)), [None]) workflow.zeta_chi_gamma_calibration_for_moments( circuit_with_calibration, []) with pytest.raises(workflow.IncompatibleMomentError): circuit_with_calibration = workflow.CircuitWithCalibration( cirq.Circuit([SQRT_ISWAP_GATE.on(a, b), cirq.Z.on(c)]), [0]) characterizations = [ PhasedFSimCalibrationResult( parameters={ (a, b): PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=0.3, gamma=0.4, phi=0.5) }, gate=SQRT_ISWAP_GATE, options=WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION, ) ] workflow.zeta_chi_gamma_calibration_for_moments( circuit_with_calibration, characterizations)
def test_override_by(): characterization = PhasedFSimCharacterization(theta=0.1, zeta=0.2, chi=0.3) other = PhasedFSimCharacterization(gamma=0.4, phi=0.5, theta=0.6) assert characterization.override_by(other) == PhasedFSimCharacterization( theta=0.6, zeta=0.2, chi=0.3, gamma=0.4, phi=0.5)
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)