def test_invalid_arguments(): with pytest.raises(ValueError, match='At least one metric must be specified'): NoiseProperties() with pytest.raises( ValueError, match='xeb, pauli error, p00, and p11 must be between 0 and 1'): NoiseProperties(p00=1.2) with pytest.raises( ValueError, match='xeb, pauli error, p00, and p11 must be between 0 and 1'): NoiseProperties(pauli_error=-0.2) with pytest.raises( ValueError, match= 'Only one of xeb fidelity, pauli error, or decay constant should be defined', ): NoiseProperties(pauli_error=0.2, xeb_fidelity=0.5) with pytest.raises(ValueError, match='A NoiseProperties object must be specified'): NoiseModelFromNoiseProperties(None)
def test_constructor_and_metrics(): prop = NoiseProperties(p00=0.2) assert prop.xeb is None assert prop.pauli_error is None assert prop.decay_constant is None assert prop.average_error() is None # These and other metrics in the file are purely for testing and # do not necessarily represent actual hardware behavior xeb_fidelity = 0.95 p00 = 0.1 t1_ns = 200.0 # Create fidelity object with a defined XEB fidelity from_xeb = NoiseProperties(xeb_fidelity=xeb_fidelity, p00=p00, t1_ns=t1_ns) assert from_xeb.p00 == p00 assert from_xeb.p11 is None assert from_xeb.t1_ns == t1_ns assert from_xeb.xeb == xeb_fidelity # Create another fidelity object with the decay constant from the first one decay_constant_from_xeb = from_xeb.decay_constant from_decay = NoiseProperties(decay_constant=decay_constant_from_xeb) # Check that their depolarization metrics match assert np.isclose(xeb_fidelity, from_decay.xeb) assert np.isclose(from_xeb.pauli_error, from_decay.pauli_error) assert np.isclose(from_xeb.average_error(), from_decay.average_error())
def test_ampl_damping_error(): t1_ns = 200.0 # Create qubits and circuit qubits = [cirq.LineQubit(0), cirq.LineQubit(1)] circuit = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([cirq.FSimGate(5 * np.pi / 2, np.pi).on_each(qubits)]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), ) # Create noise model from NoiseProperties object with specified noise prop = NoiseProperties(t1_ns=t1_ns) noise_model = NoiseModelFromNoiseProperties(prop) noisy_circuit = cirq.Circuit(noise_model.noisy_moments(circuit, qubits)) # Insert expected channels to circuit expected_circuit = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment( [cirq.amplitude_damp(1 - np.exp(-25.0 / t1_ns)).on_each(qubits)]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment( [cirq.amplitude_damp(1 - np.exp(-25.0 / t1_ns)).on_each(qubits)]), cirq.Moment([cirq.FSimGate(np.pi / 2, np.pi).on_each(qubits)]), cirq.Moment( [cirq.amplitude_damp(1 - np.exp(-12.0 / t1_ns)).on_each(qubits)]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), cirq.Moment([ cirq.amplitude_damp(1 - np.exp(-4000.0 / t1_ns)).on_each(qubits) ]), ) assert_equivalent_op_tree(expected_circuit, noisy_circuit)
def test_depolarization_error(): # Account for floating point errors # Needs Cirq issue 3965 to be resolved pauli_error = 0.09999999999999998 # Create qubits and circuit qubits = [cirq.LineQubit(0), cirq.LineQubit(1)] circuit = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([cirq.H(qubits[1])]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), ) # Create noise model from NoiseProperties object with specified noise prop = NoiseProperties(pauli_error=pauli_error) noise_model = NoiseModelFromNoiseProperties(prop) noisy_circuit = cirq.Circuit(noise_model.noisy_moments(circuit, qubits)) # Insert expected channels to circuit expected_circuit = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([cirq.depolarize(pauli_error / 3).on_each(qubits)]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([cirq.depolarize(pauli_error / 3).on_each(qubits)]), cirq.Moment([cirq.H(qubits[1])]), cirq.Moment([cirq.depolarize(pauli_error / 3).on_each(qubits)]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), cirq.Moment([cirq.depolarize(pauli_error / 3).on_each(qubits)]), ) assert_equivalent_op_tree(expected_circuit, noisy_circuit)
def test_readout_error(): p00 = 0.05 p11 = 0.1 p = p11 / (p00 + p11) gamma = p11 / p # Create qubits and circuit qubits = [cirq.LineQubit(0), cirq.LineQubit(1)] circuit = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([cirq.H(qubits[1])]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), ) # Create noise model from NoiseProperties object with specified noise prop = NoiseProperties(p00=p00, p11=p11) noise_model = NoiseModelFromNoiseProperties(prop) noisy_circuit = cirq.Circuit(noise_model.noisy_moments(circuit, qubits)) # Insert expected channels to circuit expected_circuit = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([cirq.H(qubits[1])]), cirq.Moment([ cirq.GeneralizedAmplitudeDampingChannel( p=p, gamma=gamma).on_each(qubits) ]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), ) assert_equivalent_op_tree(expected_circuit, noisy_circuit) # Create Noise Model with just p00 prop_p00 = NoiseProperties(p00=p00) noise_model_p00 = NoiseModelFromNoiseProperties(prop_p00) noisy_circuit_p00 = cirq.Circuit( noise_model_p00.noisy_moments(circuit, qubits)) # Insert expected channels to circuit expected_circuit_p00 = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([cirq.H(qubits[1])]), cirq.Moment([ cirq.GeneralizedAmplitudeDampingChannel(p=0.0, gamma=p00).on_each(qubits) ]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), ) assert_equivalent_op_tree(expected_circuit_p00, noisy_circuit_p00) # Create Noise Model with just p11 prop_p11 = NoiseProperties(p11=p11) noise_model_p11 = NoiseModelFromNoiseProperties(prop_p11) noisy_circuit_p11 = cirq.Circuit( noise_model_p11.noisy_moments(circuit, qubits)) # Insert expected channels to circuit expected_circuit_p11 = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([cirq.H(qubits[1])]), cirq.Moment([ cirq.GeneralizedAmplitudeDampingChannel(p=1.0, gamma=p11).on_each(qubits) ]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), ) assert_equivalent_op_tree(expected_circuit_p11, noisy_circuit_p11)
def test_combined_error(): # Helper function to calculate pauli error from depolarization def pauli_error_from_depolarization(pauli_error, t1_ns, duration): t2 = 2 * t1_ns pauli_error_from_t1 = (1 - np.exp(-duration / t2)) / 2 + ( 1 - np.exp(-duration / t1_ns)) / 4 if pauli_error >= pauli_error_from_t1: return pauli_error - pauli_error_from_t1 return pauli_error t1_ns = 2000.0 p11 = 0.01 # Account for floating point errors # Needs Cirq issue 3965 to be resolved pauli_error = 0.019999999999999962 # Create qubits and circuit qubits = [cirq.LineQubit(0), cirq.LineQubit(1)] circuit = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([cirq.measure(qubits[0], key='q0')]), cirq.Moment([cirq.ISwapPowGate().on_each(qubits)]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), ) # Create noise model from NoiseProperties object with specified noise prop = NoiseProperties(t1_ns=t1_ns, p11=p11, pauli_error=pauli_error) noise_model = NoiseModelFromNoiseProperties(prop) with pytest.warns( RuntimeWarning, match='Pauli error from T1 decay is greater than total Pauli error' ): noisy_circuit = cirq.Circuit(noise_model.noisy_moments( circuit, qubits)) # Insert expected channels to circuit expected_circuit = cirq.Circuit( cirq.Moment([cirq.X(qubits[0])]), cirq.Moment([ cirq.depolarize( pauli_error_from_depolarization(pauli_error, t1_ns, 25.0) / 3).on_each(qubits) ]), cirq.Moment( [cirq.amplitude_damp(1 - np.exp(-25.0 / t1_ns)).on_each(qubits)]), cirq.Moment([cirq.CNOT(qubits[0], qubits[1])]), cirq.Moment([ cirq.depolarize( pauli_error_from_depolarization(pauli_error, t1_ns, 25.0) / 3).on_each(qubits) ]), cirq.Moment( [cirq.amplitude_damp(1 - np.exp(-25.0 / t1_ns)).on_each(qubits)]), cirq.Moment([ cirq.GeneralizedAmplitudeDampingChannel(p=1.0, gamma=p11).on(qubits[0]) ]), cirq.Moment([cirq.measure(qubits[0], key='q0')]), cirq.Moment([ cirq.depolarize( pauli_error_from_depolarization(pauli_error, t1_ns, 4000.0) / 3).on_each(qubits) ]), cirq.Moment([ cirq.amplitude_damp(1 - np.exp(-4000.0 / t1_ns)).on_each(qubits) ]), cirq.Moment([cirq.ISwapPowGate().on_each(qubits)]), cirq.Moment([ cirq.depolarize( pauli_error_from_depolarization(pauli_error, t1_ns, 32.0) / 3).on_each(qubits) ]), cirq.Moment( [cirq.amplitude_damp(1 - np.exp(-32.0 / t1_ns)).on_each(qubits)]), cirq.Moment([ cirq.GeneralizedAmplitudeDampingChannel(p=1.0, gamma=p11).on_each(qubits) ]), cirq.Moment([ cirq.measure(qubits[0], key='q0'), cirq.measure(qubits[1], key='q1') ]), cirq.Moment([ cirq.depolarize( pauli_error_from_depolarization(pauli_error, t1_ns, 4000.0) / 3).on_each(qubits) ]), cirq.Moment([ cirq.amplitude_damp(1 - np.exp(-4000.0 / t1_ns)).on_each(qubits) ]), ) assert_equivalent_op_tree(expected_circuit, noisy_circuit)
def noise_properties_from_calibration(calibration: cirq_google.Calibration, validate: bool = True, tolerance: float = 0.01): """Translates between a Calibration object and a NoiseProperties object. The NoiseProperties object can then be used as input to the NoiseModelFromNoiseProperties class (cirq.devices.noise_properties) to create a NoiseModel that can be used with a simulator. If the validate argument is set to false, the depolarization decay constant will be calculated from the RB Pauli error if defined, the XEB Fidelity if RB Pauli error is not defined, or the RB Average error if the others are not defined. Args: calibration: a Calibration object with hardware metrics validate: whether or not to check that the depolarization decay constants calculated from RB Pauli error, RB average error, & XEB Fidelity agree to within a given tolerance tolerance: threshold for validating decay constants frmo RB Pauli error, RB Average error, and XEB fidelity. Raises: ValueError: decay constants from RB Average Error and RB Pauli Error aren't within tolerance ValueError: decay constants from RB Pauli Error and XEB Fidelity aren't within tolerance ValueError: decay constant from RB Pauli Error and XEB Fidelity aren't within tolerance """ # Unpack all values from Calibration object t1_micros = _unpack_from_calibration('single_qubit_idle_t1_micros', calibration) t1_nanos = t1_micros * 1000 if t1_micros is not None else None xeb_error = _unpack_from_calibration('xeb', calibration) xeb_fidelity = 1 - xeb_error if xeb_error is not None else None rb_pauli_error = _unpack_from_calibration( 'single_qubit_rb_pauli_error_per_gate', calibration) rb_average_error = _unpack_from_calibration( 'single_qubit_rb_average_error_per_gate', calibration) p00 = _unpack_from_calibration('single_qubit_p00_error', calibration) p11 = _unpack_from_calibration('single_qubit_p11_error', calibration) decay_constant_pauli = _rb_pauli_error_to_decay_constant(rb_pauli_error) decay_constant_average = _rb_average_error_to_decay_constant( rb_average_error) if validate: # Will throw error if metrics aren't compatible if not _within_tolerance(decay_constant_pauli, decay_constant_average, tolerance): raise ValueError( f'Decay constant from RB Pauli error: {decay_constant_pauli}, ' f'decay constant from RB Average error: {decay_constant_average}. ' 'If validation is disabled, RB Pauli error will be used.') decay_constant_from_xeb = _xeb_fidelity_to_decay_constant(xeb_fidelity) if not _within_tolerance(decay_constant_from_xeb, decay_constant_pauli, tolerance): raise ValueError( f'Decay constant from RB Pauli error: {decay_constant_pauli}, ' f'decay constant from XEB Fidelity: {decay_constant_from_xeb}. ' 'If validation is disabled, RB Pauli error will be used.') if not _within_tolerance(decay_constant_from_xeb, decay_constant_average, tolerance): raise ValueError( f'Decay constant from RB Average error: {decay_constant_average}, ' f'decay constant from XEB Fidelity: {decay_constant_from_xeb}. ' 'If validation is disabled, XEB Fidelity will be used.') if decay_constant_pauli is not None: # can't define both decay constant and xeb return NoiseProperties(t1_ns=t1_nanos, decay_constant=decay_constant_pauli, p00=p00, p11=p11) if xeb_fidelity is not None: return NoiseProperties(t1_ns=t1_nanos, xeb_fidelity=xeb_fidelity, p00=p00, p11=p11) return NoiseProperties(t1_ns=t1_nanos, decay_constant=decay_constant_average, p00=p00, p11=p11)