Skip to content

Commit dc1065d

Browse files
Update T1 experiment (#6487)
* T1 experiment: add A and B constants to fit, make wait times log-spaced * lowercase variable names * update tests * update tests * update tests * update tests * update tests * update tests * update tests * informative assert statements in tests * use float wait time * typecheck * nits
1 parent bc76660 commit dc1065d

File tree

2 files changed

+28
-33
lines changed

2 files changed

+28
-33
lines changed

cirq-core/cirq/experiments/t1_decay_experiment.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import Any, Optional, TYPE_CHECKING
15+
from typing import Any, Optional, Sequence, TYPE_CHECKING, cast
1616

1717
import warnings
1818
import pandas as pd
@@ -77,7 +77,12 @@ def t1_decay(
7777

7878
var = sympy.Symbol('delay_ns')
7979

80-
sweep = study.Linspace(var, start=min_delay_nanos, stop=max_delay_nanos, length=num_points)
80+
if min_delay_nanos == 0:
81+
min_delay_nanos = 0.4
82+
sweep_vals_ns = np.unique(
83+
np.round(np.logspace(np.log10(min_delay_nanos), np.log10(max_delay_nanos), num_points))
84+
)
85+
sweep = study.Points(var, cast(Sequence[float], sweep_vals_ns))
8186

8287
circuit = circuits.Circuit(
8388
ops.X(qubit), ops.wait(qubit, nanos=var), ops.measure(qubit, key='output')
@@ -118,8 +123,8 @@ def data(self) -> pd.DataFrame:
118123
def constant(self) -> float:
119124
"""The t1 decay constant."""
120125

121-
def exp_decay(x, t1):
122-
return np.exp(-x / t1)
126+
def exp_decay(x, t1, a, b):
127+
return a * np.exp(-x / t1) + b
123128

124129
xs = self._data['delay_ns']
125130
ts = self._data['true_count']
@@ -132,8 +137,8 @@ def exp_decay(x, t1):
132137

133138
# Fit to exponential decay to find the t1 constant
134139
try:
135-
popt, _ = optimize.curve_fit(exp_decay, xs, probs, p0=[t1_guess])
136-
t1 = popt[0]
140+
self.popt, _ = optimize.curve_fit(exp_decay, xs, probs, p0=[t1_guess, 1.0, 0.0])
141+
t1 = self.popt[0]
137142
return t1
138143
except RuntimeError:
139144
warnings.warn("Optimal parameters could not be found for curve fit", RuntimeWarning)
@@ -166,7 +171,9 @@ def plot(
166171
ax.plot(xs, ts / (fs + ts), 'ro-', **plot_kwargs)
167172

168173
if include_fit and not np.isnan(self.constant):
169-
ax.plot(xs, np.exp(-xs / self.constant), label='curve fit')
174+
t1 = self.constant
175+
t1, a, b = self.popt
176+
ax.plot(xs, a * np.exp(-xs / t1) + b, label='curve fit')
170177
plt.legend()
171178

172179
ax.set_xlabel(r"Delay between initialization and measurement (nanoseconds)")

cirq-core/cirq/experiments/t1_decay_experiment_test.py

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ def noisy_moment(self, moment, system_qubits):
5353
repetitions=10,
5454
max_delay=cirq.Duration(nanos=500),
5555
)
56-
results.plot()
56+
results.plot(include_fit=True)
5757

5858

5959
def test_result_eq():
6060
eq = cirq.testing.EqualsTester()
6161
eq.make_equality_group(
6262
lambda: cirq.experiments.T1DecayResult(
6363
data=pd.DataFrame(
64-
columns=['delay_ns', 'false_count', 'true_count'], index=[0], data=[[100.0, 2, 8]]
64+
columns=['delay_ns', 'false_count', 'true_count'], index=[0], data=[[100, 2, 8]]
6565
)
6666
)
6767
)
@@ -103,7 +103,7 @@ def noisy_moment(self, moment, system_qubits):
103103
data=pd.DataFrame(
104104
columns=['delay_ns', 'false_count', 'true_count'],
105105
index=range(4),
106-
data=[[100.0, 0, 10], [400.0, 0, 10], [700.0, 10, 0], [1000.0, 10, 0]],
106+
data=[[100.0, 0, 10], [215.0, 0, 10], [464.0, 0, 10], [1000.0, 10, 0]],
107107
)
108108
)
109109

@@ -117,13 +117,14 @@ def test_all_on_results():
117117
min_delay=cirq.Duration(nanos=100),
118118
max_delay=cirq.Duration(micros=1),
119119
)
120-
assert results == cirq.experiments.T1DecayResult(
120+
desired = cirq.experiments.T1DecayResult(
121121
data=pd.DataFrame(
122122
columns=['delay_ns', 'false_count', 'true_count'],
123123
index=range(4),
124-
data=[[100.0, 0, 10], [400.0, 0, 10], [700.0, 0, 10], [1000.0, 0, 10]],
124+
data=[[100.0, 0, 10], [215.0, 0, 10], [464.0, 0, 10], [1000.0, 0, 10]],
125125
)
126126
)
127+
assert results == desired, f'{results.data=} {desired.data=}'
127128

128129

129130
def test_all_off_results():
@@ -135,13 +136,14 @@ def test_all_off_results():
135136
min_delay=cirq.Duration(nanos=100),
136137
max_delay=cirq.Duration(micros=1),
137138
)
138-
assert results == cirq.experiments.T1DecayResult(
139+
desired = cirq.experiments.T1DecayResult(
139140
data=pd.DataFrame(
140141
columns=['delay_ns', 'false_count', 'true_count'],
141142
index=range(4),
142-
data=[[100.0, 10, 0], [400.0, 10, 0], [700.0, 10, 0], [1000.0, 10, 0]],
143+
data=[[100.0, 10, 0], [215.0, 10, 0], [464.0, 10, 0], [1000.0, 10, 0]],
143144
)
144145
)
146+
assert results == desired, f'{results.data=} {desired.data=}'
145147

146148

147149
@pytest.mark.usefixtures('closefigures')
@@ -150,28 +152,14 @@ def test_curve_fit_plot_works():
150152
data=pd.DataFrame(
151153
columns=['delay_ns', 'false_count', 'true_count'],
152154
index=range(4),
153-
data=[[100.0, 6, 4], [400.0, 10, 0], [700.0, 10, 0], [1000.0, 10, 0]],
155+
data=[[100.0, 6, 4], [215.0, 10, 0], [464.0, 10, 0], [1000.0, 10, 0]],
154156
)
155157
)
156158

157159
good_fit.plot(include_fit=True)
158160

159161

160-
@pytest.mark.usefixtures('closefigures')
161-
def test_curve_fit_plot_warning():
162-
bad_fit = cirq.experiments.T1DecayResult(
163-
data=pd.DataFrame(
164-
columns=['delay_ns', 'false_count', 'true_count'],
165-
index=range(4),
166-
data=[[100.0, 10, 0], [400.0, 10, 0], [700.0, 10, 0], [1000.0, 10, 0]],
167-
)
168-
)
169-
170-
with pytest.warns(RuntimeWarning, match='Optimal parameters could not be found for curve fit'):
171-
bad_fit.plot(include_fit=True)
172-
173-
174-
@pytest.mark.parametrize('t1', [200, 500, 700])
162+
@pytest.mark.parametrize('t1', [200.0, 500.0, 700.0])
175163
def test_noise_model_continous(t1):
176164
class GradualDecay(cirq.NoiseModel):
177165
def __init__(self, t1: float):
@@ -196,10 +184,10 @@ def noisy_moment(self, moment, system_qubits):
196184
results = cirq.experiments.t1_decay(
197185
sampler=cirq.DensityMatrixSimulator(noise=GradualDecay(t1)),
198186
qubit=cirq.GridQubit(0, 0),
199-
num_points=4,
187+
num_points=10,
200188
repetitions=10,
201-
min_delay=cirq.Duration(nanos=100),
202-
max_delay=cirq.Duration(micros=1),
189+
min_delay=cirq.Duration(nanos=1),
190+
max_delay=cirq.Duration(micros=10),
203191
)
204192

205193
assert np.isclose(results.constant, t1, 50)

0 commit comments

Comments
 (0)