Skip to content

Commit

Permalink
T1 decay for simulator (#4326)
Browse files Browse the repository at this point in the history
When using a simulator, noise is applied after each gate. Previously, in the t1 decay method, there's only one wait gate, which means that noise is not properly applied "over time" when using a simulator. I've updated the method to add a number of wait gates proportional to the length of the delay when using a simulator.

Related to Issue #[4264](#4264)

As always, any feedback is appreciated!
  • Loading branch information
asmuzsoy committed Aug 6, 2021
1 parent e56e15d commit c3f9a5d
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 27 deletions.
5 changes: 4 additions & 1 deletion cirq-core/cirq/experiments/t1_decay_experiment.py
Expand Up @@ -67,7 +67,10 @@ def t1_decay(
var = sympy.Symbol('delay_ns')

sweep = study.Linspace(
var, start=min_delay_dur.total_nanos(), stop=max_delay_dur.total_nanos(), length=num_points
var,
start=min_delay_dur.total_nanos(),
stop=max_delay_dur.total_nanos(),
length=num_points,
)

circuit = circuits.Circuit(
Expand Down
80 changes: 54 additions & 26 deletions cirq-core/cirq/experiments/t1_decay_experiment_test.py
Expand Up @@ -167,32 +167,6 @@ def test_all_off_results():
)


@pytest.mark.parametrize(
't1, data',
[
(100, [[100.0, 6, 4], [400.0, 10, 0], [700.0, 10, 0], [1000.0, 10, 0]]),
(400, [[100.0, 0, 10], [400.0, 6, 4], [700.0, 10, 0], [1000.0, 10, 0]]),
(
200,
[
[time, int(np.exp(-time / 200)), 10 - int(np.exp(-time / 200))]
for time in np.linspace(0, 1000, 100)
],
),
],
)
def test_constant(t1, data):
result = cirq.experiments.T1DecayResult(
data=pd.DataFrame(
columns=['delay_ns', 'false_count', 'true_count'],
index=range(len(data)),
data=data,
)
)

assert np.isclose(result.constant, t1, 5)


def test_curve_fit_plot_works():
good_fit = cirq.experiments.T1DecayResult(
data=pd.DataFrame(
Expand Down Expand Up @@ -228,6 +202,60 @@ def test_curve_fit_plot_warning():
bad_fit.plot(include_fit=True)


@pytest.mark.parametrize('t1', [200, 500, 700])
def test_noise_model_continous(t1):
class GradualDecay(cirq.NoiseModel):
def __init__(self, t1: float):
self.t1 = t1

def noisy_moment(self, moment, system_qubits):
duration = max(
(
op.gate.duration
for op in moment.operations
if isinstance(op.gate, cirq.WaitGate)
),
default=cirq.Duration(nanos=0),
)
if duration > cirq.Duration(nanos=0):
# Found a wait gate in this moment.
return cirq.amplitude_damp(1 - np.exp(-duration.total_nanos() / self.t1)).on_each(
system_qubits
)
return moment

results = cirq.experiments.t1_decay(
sampler=cirq.DensityMatrixSimulator(noise=GradualDecay(t1)),
qubit=cirq.GridQubit(0, 0),
num_points=4,
repetitions=10,
min_delay=cirq.Duration(nanos=100),
max_delay=cirq.Duration(micros=1),
)

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


@pytest.mark.parametrize('gamma', [0.01, 0.05, 0.1])
def test_noise_model_discrete(gamma):
results = cirq.experiments.t1_decay(
sampler=cirq.DensityMatrixSimulator(
noise=cirq.NoiseModel.from_noise_model_like(cirq.amplitude_damp(gamma))
),
qubit=cirq.GridQubit(0, 0),
num_points=4,
repetitions=100,
min_delay=cirq.Duration(nanos=100),
max_delay=cirq.Duration(micros=1),
)

data = results.data
probs = data['true_count'] / (data['true_count'] + data['false_count'])

# Check that there is no decay in probability over time
np.testing.assert_allclose(probs, np.mean(probs), atol=0.2)


def test_bad_args():
with pytest.raises(ValueError, match='repetitions <= 0'):
_ = cirq.experiments.t1_decay(
Expand Down

0 comments on commit c3f9a5d

Please sign in to comment.