|
| 1 | +import pytest |
| 2 | +import cirq_google |
| 3 | +from cirq_google.api import v2 |
| 4 | +from cirq_google.experimental.noise_models.calibration_to_noise_properties import ( |
| 5 | + noise_properties_from_calibration, |
| 6 | +) |
| 7 | +from google.protobuf.text_format import Merge |
| 8 | +import numpy as np |
| 9 | + |
| 10 | + |
| 11 | +def test_noise_properties_from_calibration(): |
| 12 | + xeb_1 = 0.999 |
| 13 | + xeb_2 = 0.996 |
| 14 | + |
| 15 | + p00_1 = 0.001 |
| 16 | + p00_2 = 0.002 |
| 17 | + p00_3 = 0.003 |
| 18 | + |
| 19 | + t1_1 = 0.005 |
| 20 | + t1_2 = 0.007 |
| 21 | + t1_3 = 0.003 |
| 22 | + |
| 23 | + _CALIBRATION_DATA = Merge( |
| 24 | + f""" |
| 25 | + timestamp_ms: 1579214873, |
| 26 | + metrics: [{{ |
| 27 | + name: 'xeb', |
| 28 | + targets: ['0_0', '0_1'], |
| 29 | + values: [{{ |
| 30 | + double_val: {xeb_1} |
| 31 | + }}] |
| 32 | + }}, {{ |
| 33 | + name: 'xeb', |
| 34 | + targets: ['0_0', '1_0'], |
| 35 | + values: [{{ |
| 36 | + double_val:{xeb_2} |
| 37 | + }}] |
| 38 | + }}, {{ |
| 39 | + name: 'single_qubit_p00_error', |
| 40 | + targets: ['0_0'], |
| 41 | + values: [{{ |
| 42 | + double_val: {p00_1} |
| 43 | + }}] |
| 44 | + }}, {{ |
| 45 | + name: 'single_qubit_p00_error', |
| 46 | + targets: ['0_1'], |
| 47 | + values: [{{ |
| 48 | + double_val: {p00_2} |
| 49 | + }}] |
| 50 | + }}, {{ |
| 51 | + name: 'single_qubit_p00_error', |
| 52 | + targets: ['1_0'], |
| 53 | + values: [{{ |
| 54 | + double_val: {p00_3} |
| 55 | + }}] |
| 56 | + }}, {{ |
| 57 | + name: 'single_qubit_readout_separation_error', |
| 58 | + targets: ['0_0'], |
| 59 | + values: [{{ |
| 60 | + double_val: .004 |
| 61 | + }}] |
| 62 | + }}, {{ |
| 63 | + name: 'single_qubit_readout_separation_error', |
| 64 | + targets: ['0_1'], |
| 65 | + values: [{{ |
| 66 | + double_val: .005 |
| 67 | + }}] |
| 68 | + }},{{ |
| 69 | + name: 'single_qubit_readout_separation_error', |
| 70 | + targets: ['1_0'], |
| 71 | + values: [{{ |
| 72 | + double_val: .006 |
| 73 | + }}] |
| 74 | + }}, {{ |
| 75 | + name: 'single_qubit_idle_t1_micros', |
| 76 | + targets: ['0_0'], |
| 77 | + values: [{{ |
| 78 | + double_val: {t1_1} |
| 79 | + }}] |
| 80 | + }}, {{ |
| 81 | + name: 'single_qubit_idle_t1_micros', |
| 82 | + targets: ['0_1'], |
| 83 | + values: [{{ |
| 84 | + double_val: {t1_2} |
| 85 | + }}] |
| 86 | + }}, {{ |
| 87 | + name: 'single_qubit_idle_t1_micros', |
| 88 | + targets: ['1_0'], |
| 89 | + values: [{{ |
| 90 | + double_val: {t1_3} |
| 91 | + }}] |
| 92 | + }}] |
| 93 | +""", |
| 94 | + v2.metrics_pb2.MetricsSnapshot(), |
| 95 | + ) |
| 96 | + |
| 97 | + # Create NoiseProperties object from Calibration |
| 98 | + calibration = cirq_google.Calibration(_CALIBRATION_DATA) |
| 99 | + prop = noise_properties_from_calibration(calibration) |
| 100 | + |
| 101 | + expected_t1_nanos = np.mean([t1_1, t1_2, t1_3]) * 1000 |
| 102 | + expected_xeb_fidelity = np.mean([xeb_1, xeb_2]) |
| 103 | + expected_p00 = np.mean([p00_1, p00_2, p00_3]) |
| 104 | + |
| 105 | + assert np.isclose(prop.t1_ns, expected_t1_nanos) |
| 106 | + assert np.isclose(prop.xeb, expected_xeb_fidelity) |
| 107 | + assert np.isclose(prop.p00, expected_p00) |
| 108 | + |
| 109 | + |
| 110 | +def test_from_calibration_rb(): |
| 111 | + rb_pauli_1 = 0.001 |
| 112 | + rb_pauli_2 = 0.002 |
| 113 | + rb_pauli_3 = 0.003 |
| 114 | + |
| 115 | + _CALIBRATION_DATA_RB = Merge( |
| 116 | + f""" |
| 117 | + timestamp_ms: 1579214873, |
| 118 | + metrics: [{{ |
| 119 | +
|
| 120 | + name: 'single_qubit_rb_pauli_error_per_gate', |
| 121 | + targets: ['0_0'], |
| 122 | + values: [{{ |
| 123 | + double_val: {rb_pauli_1} |
| 124 | + }}] |
| 125 | + }}, {{ |
| 126 | + name: 'single_qubit_rb_pauli_error_per_gate', |
| 127 | + targets: ['0_1'], |
| 128 | + values: [{{ |
| 129 | + double_val: {rb_pauli_2} |
| 130 | + }}] |
| 131 | + }}, {{ |
| 132 | + name: 'single_qubit_rb_pauli_error_per_gate', |
| 133 | + targets: ['1_0'], |
| 134 | + values: [{{ |
| 135 | + double_val: {rb_pauli_3} |
| 136 | + }}] |
| 137 | + }}] |
| 138 | + """, |
| 139 | + v2.metrics_pb2.MetricsSnapshot(), |
| 140 | + ) |
| 141 | + |
| 142 | + # Create NoiseProperties object from Calibration |
| 143 | + rb_calibration = cirq_google.Calibration(_CALIBRATION_DATA_RB) |
| 144 | + rb_noise_prop = noise_properties_from_calibration(rb_calibration) |
| 145 | + |
| 146 | + average_pauli_rb = np.mean([rb_pauli_1, rb_pauli_2, rb_pauli_3]) |
| 147 | + assert np.isclose(average_pauli_rb, rb_noise_prop.pauli_error) |
| 148 | + |
| 149 | + |
| 150 | +def test_validate_calibration(): |
| 151 | + # RB Pauli error and RB Average Error disagree |
| 152 | + rb_pauli_error = 0.05 |
| 153 | + rb_average_error = 0.1 |
| 154 | + |
| 155 | + decay_constant_pauli = 1 - rb_pauli_error / (1 - 1 / 4) |
| 156 | + decay_constant_average = 1 - rb_average_error / (1 - 1 / 2) |
| 157 | + _CALIBRATION_DATA_PAULI_AVERAGE = Merge( |
| 158 | + f""" |
| 159 | + timestamp_ms: 1579214873, |
| 160 | + metrics: [{{ |
| 161 | +
|
| 162 | + name: 'single_qubit_rb_pauli_error_per_gate', |
| 163 | + targets: ['0_0'], |
| 164 | + values: [{{ |
| 165 | + double_val: {rb_pauli_error} |
| 166 | + }}] |
| 167 | + }}, {{ |
| 168 | + name: 'single_qubit_rb_average_error_per_gate', |
| 169 | + targets: ['0_1'], |
| 170 | + values: [{{ |
| 171 | + double_val: {rb_average_error} |
| 172 | + }}] |
| 173 | + }}] |
| 174 | + """, |
| 175 | + v2.metrics_pb2.MetricsSnapshot(), |
| 176 | + ) |
| 177 | + bad_calibration_pauli_average = cirq_google.Calibration(_CALIBRATION_DATA_PAULI_AVERAGE) |
| 178 | + with pytest.raises( |
| 179 | + ValueError, |
| 180 | + match=f'Decay constant from RB Pauli error: {decay_constant_pauli}, ' |
| 181 | + f'decay constant from RB Average error: {decay_constant_average}. ' |
| 182 | + 'If validation is disabled, RB Pauli error will be used.', |
| 183 | + ): |
| 184 | + noise_properties_from_calibration(bad_calibration_pauli_average) |
| 185 | + |
| 186 | + assert np.isclose( |
| 187 | + noise_properties_from_calibration( |
| 188 | + bad_calibration_pauli_average, validate=False |
| 189 | + ).pauli_error, |
| 190 | + rb_pauli_error, |
| 191 | + ) |
| 192 | + |
| 193 | + # RB Pauli Error and XEB Fidelity disagree |
| 194 | + xeb_fidelity = 0.99 |
| 195 | + |
| 196 | + decay_constant_from_xeb = 1 - (1 - xeb_fidelity) / (1 - 1 / 4) |
| 197 | + |
| 198 | + _CALIBRATION_DATA_PAULI_XEB = Merge( |
| 199 | + f""" |
| 200 | + timestamp_ms: 1579214873, |
| 201 | + metrics: [{{ |
| 202 | +
|
| 203 | + name: 'single_qubit_rb_pauli_error_per_gate', |
| 204 | + targets: ['0_0'], |
| 205 | + values: [{{ |
| 206 | + double_val: {rb_pauli_error} |
| 207 | + }}] |
| 208 | + }}, {{ |
| 209 | + name: 'xeb', |
| 210 | + targets: ['0_0', '1_0'], |
| 211 | + values: [{{ |
| 212 | + double_val:{xeb_fidelity} |
| 213 | + }}] |
| 214 | + }}] |
| 215 | + """, |
| 216 | + v2.metrics_pb2.MetricsSnapshot(), |
| 217 | + ) |
| 218 | + |
| 219 | + bad_calibration_pauli_xeb = cirq_google.Calibration(_CALIBRATION_DATA_PAULI_XEB) |
| 220 | + with pytest.raises( |
| 221 | + ValueError, |
| 222 | + match=f'Decay constant from RB Pauli error: {decay_constant_pauli}, ' |
| 223 | + f'decay constant from XEB Fidelity: {decay_constant_from_xeb}. ' |
| 224 | + 'If validation is disabled, RB Pauli error will be used.', |
| 225 | + ): |
| 226 | + noise_properties_from_calibration(bad_calibration_pauli_xeb) |
| 227 | + |
| 228 | + # RB Average Error and XEB Fidelity disagree |
| 229 | + _CALIBRATION_DATA_AVERAGE_XEB = Merge( |
| 230 | + f""" |
| 231 | + timestamp_ms: 1579214873, |
| 232 | + metrics: [{{ |
| 233 | +
|
| 234 | + name: 'single_qubit_rb_average_error_per_gate', |
| 235 | + targets: ['0_0'], |
| 236 | + values: [{{ |
| 237 | + double_val: {rb_average_error} |
| 238 | + }}] |
| 239 | + }}, {{ |
| 240 | + name: 'xeb', |
| 241 | + targets: ['0_0', '1_0'], |
| 242 | + values: [{{ |
| 243 | + double_val:{xeb_fidelity} |
| 244 | + }}] |
| 245 | + }}] |
| 246 | + """, |
| 247 | + v2.metrics_pb2.MetricsSnapshot(), |
| 248 | + ) |
| 249 | + |
| 250 | + bad_calibration_average_xeb = cirq_google.Calibration(_CALIBRATION_DATA_AVERAGE_XEB) |
| 251 | + with pytest.raises( |
| 252 | + ValueError, |
| 253 | + match=f'Decay constant from RB Average error: {decay_constant_average}, ' |
| 254 | + f'decay constant from XEB Fidelity: {decay_constant_from_xeb}. ' |
| 255 | + 'If validation is disabled, XEB Fidelity will be used.', |
| 256 | + ): |
| 257 | + noise_properties_from_calibration(bad_calibration_average_xeb) |
| 258 | + |
| 259 | + assert np.isclose( |
| 260 | + noise_properties_from_calibration(bad_calibration_average_xeb, validate=False).xeb, |
| 261 | + xeb_fidelity, |
| 262 | + ) |
| 263 | + |
| 264 | + # Calibration data with no RB error or XEB fidelity |
| 265 | + t1 = 2.0 # microseconds |
| 266 | + |
| 267 | + _CALIBRATION_DATA_T1 = Merge( |
| 268 | + f""" |
| 269 | + timestamp_ms: 1579214873, |
| 270 | + metrics: [{{ |
| 271 | + name: 'single_qubit_idle_t1_micros', |
| 272 | + targets: ['0_0'], |
| 273 | + values: [{{ |
| 274 | + double_val: {t1} |
| 275 | + }}] |
| 276 | + }}] |
| 277 | + """, |
| 278 | + v2.metrics_pb2.MetricsSnapshot(), |
| 279 | + ) |
| 280 | + |
| 281 | + calibration_t1 = cirq_google.Calibration(_CALIBRATION_DATA_T1) |
| 282 | + |
| 283 | + assert np.isclose(noise_properties_from_calibration(calibration_t1).t1_ns, t1 * 1000) |
0 commit comments