Skip to content

Commit f1aacd7

Browse files
[Refactoring]: split devices.noise_utils into qis.noise_utils and devices.noise_utils (#6453)
1 parent ab9e10a commit f1aacd7

6 files changed

+266
-117
lines changed

cirq-core/cirq/devices/noise_utils.py

+33-31
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@
1313
# limitations under the License.
1414

1515
from typing import TYPE_CHECKING, Any, Dict, Tuple, Type, Union
16-
import numpy as np
1716

18-
from cirq import ops, protocols, value
19-
from cirq._compat import proper_repr
17+
from cirq import ops, protocols, value, qis
18+
from cirq._compat import proper_repr, deprecated
2019

2120
if TYPE_CHECKING:
2221
import cirq
@@ -97,8 +96,10 @@ def _from_json_dict_(cls, gate_type, qubits, **kwargs) -> 'OpIdentifier':
9796
return cls(gate_type, *qubits)
9897

9998

100-
# TODO: expose all from top-level cirq?
101-
def decay_constant_to_xeb_fidelity(decay_constant: float, num_qubits: int = 2) -> float:
99+
@deprecated(deadline='v2.0', fix='use cirq.qis.decay_constant_to_xeb_fidelity')
100+
def decay_constant_to_xeb_fidelity(
101+
decay_constant: float, num_qubits: int = 2
102+
) -> float: # pragma: no cover
102103
"""Calculates the XEB fidelity from the depolarization decay constant.
103104
104105
Args:
@@ -108,11 +109,13 @@ def decay_constant_to_xeb_fidelity(decay_constant: float, num_qubits: int = 2) -
108109
Returns:
109110
Calculated XEB fidelity.
110111
"""
111-
N = 2**num_qubits
112-
return 1 - ((1 - decay_constant) * (1 - 1 / N))
112+
return qis.decay_constant_to_xeb_fidelity(decay_constant, num_qubits)
113113

114114

115-
def decay_constant_to_pauli_error(decay_constant: float, num_qubits: int = 1) -> float:
115+
@deprecated(deadline='v2.0', fix='use cirq.qis.decay_constant_to_pauli_error')
116+
def decay_constant_to_pauli_error(
117+
decay_constant: float, num_qubits: int = 1
118+
) -> float: # pragma: no cover
116119
"""Calculates pauli error from the depolarization decay constant.
117120
118121
Args:
@@ -122,11 +125,13 @@ def decay_constant_to_pauli_error(decay_constant: float, num_qubits: int = 1) ->
122125
Returns:
123126
Calculated Pauli error.
124127
"""
125-
N = 2**num_qubits
126-
return (1 - decay_constant) * (1 - 1 / N / N)
128+
return qis.decay_constant_to_pauli_error(decay_constant, num_qubits)
127129

128130

129-
def pauli_error_to_decay_constant(pauli_error: float, num_qubits: int = 1) -> float:
131+
@deprecated(deadline='v2.0', fix='use cirq.qis.pauli_error_to_decay_constant')
132+
def pauli_error_to_decay_constant(
133+
pauli_error: float, num_qubits: int = 1
134+
) -> float: # pragma: no cover
130135
"""Calculates depolarization decay constant from pauli error.
131136
132137
Args:
@@ -136,11 +141,13 @@ def pauli_error_to_decay_constant(pauli_error: float, num_qubits: int = 1) -> fl
136141
Returns:
137142
Calculated depolarization decay constant.
138143
"""
139-
N = 2**num_qubits
140-
return 1 - (pauli_error / (1 - 1 / N / N))
144+
return qis.pauli_error_to_decay_constant(pauli_error, num_qubits)
141145

142146

143-
def xeb_fidelity_to_decay_constant(xeb_fidelity: float, num_qubits: int = 2) -> float:
147+
@deprecated(deadline='v2.0', fix='use cirq.qis.xeb_fidelity_to_decay_constant')
148+
def xeb_fidelity_to_decay_constant(
149+
xeb_fidelity: float, num_qubits: int = 2
150+
) -> float: # pragma: no cover
144151
"""Calculates the depolarization decay constant from XEB fidelity.
145152
146153
Args:
@@ -150,11 +157,11 @@ def xeb_fidelity_to_decay_constant(xeb_fidelity: float, num_qubits: int = 2) ->
150157
Returns:
151158
Calculated depolarization decay constant.
152159
"""
153-
N = 2**num_qubits
154-
return 1 - (1 - xeb_fidelity) / (1 - 1 / N)
160+
return qis.xeb_fidelity_to_decay_constant(xeb_fidelity, num_qubits)
155161

156162

157-
def pauli_error_from_t1(t_ns: float, t1_ns: float) -> float:
163+
@deprecated(deadline='v2.0', fix='use cirq.qis.pauli_error_from_t1')
164+
def pauli_error_from_t1(t_ns: float, t1_ns: float) -> float: # pragma: no cover
158165
"""Calculates the pauli error from T1 decay constant.
159166
160167
This computes error for a specific duration, `t`.
@@ -166,11 +173,11 @@ def pauli_error_from_t1(t_ns: float, t1_ns: float) -> float:
166173
Returns:
167174
Calculated Pauli error resulting from T1 decay.
168175
"""
169-
t2 = 2 * t1_ns
170-
return (1 - np.exp(-t_ns / t2)) / 2 + (1 - np.exp(-t_ns / t1_ns)) / 4
176+
return qis.pauli_error_from_t1(t_ns, t1_ns)
171177

172178

173-
def average_error(decay_constant: float, num_qubits: int = 1) -> float:
179+
@deprecated(deadline='v2.0', fix='use cirq.qis.average_error')
180+
def average_error(decay_constant: float, num_qubits: int = 1) -> float: # pragma: no cover
174181
"""Calculates the average error from the depolarization decay constant.
175182
176183
Args:
@@ -180,11 +187,13 @@ def average_error(decay_constant: float, num_qubits: int = 1) -> float:
180187
Returns:
181188
Calculated average error.
182189
"""
183-
N = 2**num_qubits
184-
return (1 - decay_constant) * (1 - 1 / N)
190+
return qis.average_error(decay_constant, num_qubits)
185191

186192

187-
def decoherence_pauli_error(t1_ns: float, tphi_ns: float, gate_time_ns: float) -> float:
193+
@deprecated(deadline='v2.0', fix='use cirq.qis.decoherence_pauli_error')
194+
def decoherence_pauli_error(
195+
t1_ns: float, tphi_ns: float, gate_time_ns: float
196+
) -> float: # pragma: no cover
188197
"""The component of Pauli error caused by decoherence on a single qubit.
189198
190199
Args:
@@ -195,11 +204,4 @@ def decoherence_pauli_error(t1_ns: float, tphi_ns: float, gate_time_ns: float) -
195204
Returns:
196205
Calculated Pauli error resulting from decoherence.
197206
"""
198-
gamma_2 = (1 / (2 * t1_ns)) + 1 / tphi_ns
199-
200-
exp1 = np.exp(-gate_time_ns / t1_ns)
201-
exp2 = np.exp(-gate_time_ns * gamma_2)
202-
px = 0.25 * (1 - exp1)
203-
py = px
204-
pz = 0.5 * (1 - exp2) - px
205-
return px + py + pz
207+
return qis.decoherence_pauli_error(t1_ns, tphi_ns, gate_time_ns)

cirq-core/cirq/devices/noise_utils_test.py

+1-84
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import numpy as np
16-
import pytest
17-
1815
import cirq
19-
from cirq.devices.noise_utils import (
20-
OpIdentifier,
21-
decay_constant_to_xeb_fidelity,
22-
decay_constant_to_pauli_error,
23-
pauli_error_to_decay_constant,
24-
xeb_fidelity_to_decay_constant,
25-
pauli_error_from_t1,
26-
average_error,
27-
decoherence_pauli_error,
28-
)
16+
from cirq.devices.noise_utils import OpIdentifier
2917

3018

3119
def test_op_identifier():
@@ -67,74 +55,3 @@ def test_op_id_instance():
6755
gate = cirq.SingleQubitCliffordGate.from_xz_map((cirq.X, False), (cirq.Z, False))
6856
op_id = OpIdentifier(gate, q0)
6957
cirq.testing.assert_equivalent_repr(op_id)
70-
71-
72-
@pytest.mark.parametrize(
73-
'decay_constant,num_qubits,expected_output',
74-
[(0.01, 1, 1 - (0.99 * 1 / 2)), (0.05, 2, 1 - (0.95 * 3 / 4))],
75-
)
76-
def test_decay_constant_to_xeb_fidelity(decay_constant, num_qubits, expected_output):
77-
val = decay_constant_to_xeb_fidelity(decay_constant, num_qubits)
78-
assert val == expected_output
79-
80-
81-
@pytest.mark.parametrize(
82-
'decay_constant,num_qubits,expected_output',
83-
[(0.01, 1, 0.99 * 3 / 4), (0.05, 2, 0.95 * 15 / 16)],
84-
)
85-
def test_decay_constant_to_pauli_error(decay_constant, num_qubits, expected_output):
86-
val = decay_constant_to_pauli_error(decay_constant, num_qubits)
87-
assert val == expected_output
88-
89-
90-
@pytest.mark.parametrize(
91-
'pauli_error,num_qubits,expected_output',
92-
[(0.01, 1, 1 - (0.01 / (3 / 4))), (0.05, 2, 1 - (0.05 / (15 / 16)))],
93-
)
94-
def test_pauli_error_to_decay_constant(pauli_error, num_qubits, expected_output):
95-
val = pauli_error_to_decay_constant(pauli_error, num_qubits)
96-
assert val == expected_output
97-
98-
99-
@pytest.mark.parametrize(
100-
'xeb_fidelity,num_qubits,expected_output',
101-
[(0.01, 1, 1 - 0.99 / (1 / 2)), (0.05, 2, 1 - 0.95 / (3 / 4))],
102-
)
103-
def test_xeb_fidelity_to_decay_constant(xeb_fidelity, num_qubits, expected_output):
104-
val = xeb_fidelity_to_decay_constant(xeb_fidelity, num_qubits)
105-
assert val == expected_output
106-
107-
108-
@pytest.mark.parametrize(
109-
't,t1_ns,expected_output',
110-
[
111-
(20, 1e5, (1 - np.exp(-20 / 2e5)) / 2 + (1 - np.exp(-20 / 1e5)) / 4),
112-
(4000, 1e4, (1 - np.exp(-4000 / 2e4)) / 2 + (1 - np.exp(-4000 / 1e4)) / 4),
113-
],
114-
)
115-
def test_pauli_error_from_t1(t, t1_ns, expected_output):
116-
val = pauli_error_from_t1(t, t1_ns)
117-
assert val == expected_output
118-
119-
120-
@pytest.mark.parametrize(
121-
'decay_constant,num_qubits,expected_output', [(0.01, 1, 0.99 * 1 / 2), (0.05, 2, 0.95 * 3 / 4)]
122-
)
123-
def test_average_error(decay_constant, num_qubits, expected_output):
124-
val = average_error(decay_constant, num_qubits)
125-
assert val == expected_output
126-
127-
128-
@pytest.mark.parametrize(
129-
'T1_ns,Tphi_ns,gate_time_ns', [(1e4, 2e4, 25), (1e5, 2e3, 25), (1e4, 2e4, 4000)]
130-
)
131-
def test_decoherence_pauli_error(T1_ns, Tphi_ns, gate_time_ns):
132-
val = decoherence_pauli_error(T1_ns, Tphi_ns, gate_time_ns)
133-
# Expected value is of the form:
134-
#
135-
# (1/4) * [1 - e^(-t/T1)] + (1/2) * [1 - e^(-t/(2*T1) - t/Tphi]
136-
#
137-
expected_output = 0.25 * (1 - np.exp(-gate_time_ns / T1_ns)) + 0.5 * (
138-
1 - np.exp(-gate_time_ns * ((1 / (2 * T1_ns)) + 1 / Tphi_ns))
139-
)
140-
assert val == expected_output

cirq-core/cirq/devices/superconducting_qubits_noise_properties.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from functools import cached_property
2121
from typing import Dict, TYPE_CHECKING, List, Set, Type
2222

23-
from cirq import ops, devices
23+
from cirq import ops, devices, qis
2424
from cirq.devices import noise_utils
2525

2626
if TYPE_CHECKING:
@@ -129,7 +129,7 @@ def expected_gates(cls) -> Set[Type[ops.Gate]]:
129129
def _get_pauli_error(self, p_error: float, op_id: noise_utils.OpIdentifier):
130130
time_ns = float(self.gate_times_ns[op_id.gate_type])
131131
for q in op_id.qubits:
132-
p_error -= noise_utils.decoherence_pauli_error(self.t1_ns[q], self.tphi_ns[q], time_ns)
132+
p_error -= qis.decoherence_pauli_error(self.t1_ns[q], self.tphi_ns[q], time_ns)
133133
return p_error
134134

135135
@cached_property

cirq-core/cirq/qis/__init__.py

+10
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,13 @@
5050
validate_qid_shape,
5151
validate_normalized_state_vector,
5252
)
53+
54+
from cirq.qis.noise_utils import (
55+
decay_constant_to_xeb_fidelity,
56+
decay_constant_to_pauli_error,
57+
pauli_error_to_decay_constant,
58+
xeb_fidelity_to_decay_constant,
59+
pauli_error_from_t1,
60+
average_error,
61+
decoherence_pauli_error,
62+
)

cirq-core/cirq/qis/noise_utils.py

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Copyright 2021 The Cirq Developers
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import numpy as np
16+
17+
18+
# TODO: expose all from top-level cirq?
19+
def decay_constant_to_xeb_fidelity(decay_constant: float, num_qubits: int = 2) -> float:
20+
"""Calculates the XEB fidelity from the depolarization decay constant.
21+
22+
Args:
23+
decay_constant: Depolarization decay constant.
24+
num_qubits: Number of qubits.
25+
26+
Returns:
27+
Calculated XEB fidelity.
28+
"""
29+
N = 2**num_qubits
30+
return 1 - ((1 - decay_constant) * (1 - 1 / N))
31+
32+
33+
def decay_constant_to_pauli_error(decay_constant: float, num_qubits: int = 1) -> float:
34+
"""Calculates pauli error from the depolarization decay constant.
35+
36+
Args:
37+
decay_constant: Depolarization decay constant.
38+
num_qubits: Number of qubits.
39+
40+
Returns:
41+
Calculated Pauli error.
42+
"""
43+
N = 2**num_qubits
44+
return (1 - decay_constant) * (1 - 1 / N / N)
45+
46+
47+
def pauli_error_to_decay_constant(pauli_error: float, num_qubits: int = 1) -> float:
48+
"""Calculates depolarization decay constant from pauli error.
49+
50+
Args:
51+
pauli_error: The pauli error.
52+
num_qubits: Number of qubits.
53+
54+
Returns:
55+
Calculated depolarization decay constant.
56+
"""
57+
N = 2**num_qubits
58+
return 1 - (pauli_error / (1 - 1 / N / N))
59+
60+
61+
def xeb_fidelity_to_decay_constant(xeb_fidelity: float, num_qubits: int = 2) -> float:
62+
"""Calculates the depolarization decay constant from XEB fidelity.
63+
64+
Args:
65+
xeb_fidelity: The XEB fidelity.
66+
num_qubits: Number of qubits.
67+
68+
Returns:
69+
Calculated depolarization decay constant.
70+
"""
71+
N = 2**num_qubits
72+
return 1 - (1 - xeb_fidelity) / (1 - 1 / N)
73+
74+
75+
def pauli_error_from_t1(t_ns: float, t1_ns: float) -> float:
76+
"""Calculates the pauli error from T1 decay constant.
77+
78+
This computes error for a specific duration, `t`.
79+
80+
Args:
81+
t_ns: The duration of the gate in ns.
82+
t1_ns: The T1 decay constant in ns.
83+
84+
Returns:
85+
Calculated Pauli error resulting from T1 decay.
86+
"""
87+
t2 = 2 * t1_ns
88+
return (1 - np.exp(-t_ns / t2)) / 2 + (1 - np.exp(-t_ns / t1_ns)) / 4
89+
90+
91+
def average_error(decay_constant: float, num_qubits: int = 1) -> float:
92+
"""Calculates the average error from the depolarization decay constant.
93+
94+
Args:
95+
decay_constant: Depolarization decay constant.
96+
num_qubits: Number of qubits.
97+
98+
Returns:
99+
Calculated average error.
100+
"""
101+
N = 2**num_qubits
102+
return (1 - decay_constant) * (1 - 1 / N)
103+
104+
105+
def decoherence_pauli_error(t1_ns: float, tphi_ns: float, gate_time_ns: float) -> float:
106+
"""The component of Pauli error caused by decoherence on a single qubit.
107+
108+
Args:
109+
t1_ns: T1 time in nanoseconds.
110+
tphi_ns: Tphi time in nanoseconds.
111+
gate_time_ns: Duration in nanoseconds of the gate affected by this error.
112+
113+
Returns:
114+
Calculated Pauli error resulting from decoherence.
115+
"""
116+
gamma_2 = (1 / (2 * t1_ns)) + 1 / tphi_ns
117+
118+
exp1 = np.exp(-gate_time_ns / t1_ns)
119+
exp2 = np.exp(-gate_time_ns * gamma_2)
120+
px = 0.25 * (1 - exp1)
121+
py = px
122+
pz = 0.5 * (1 - exp2) - px
123+
return px + py + pz

0 commit comments

Comments
 (0)