cirq-core 1.6.0.dev20250516060316__py3-none-any.whl → 1.6.0.dev20250517012327__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cirq-core might be problematic. Click here for more details.
- cirq/__init__.py +1 -0
- cirq/_import_test.py +2 -2
- cirq/_version.py +1 -1
- cirq/_version_test.py +1 -1
- cirq/interop/quirk/cells/parse_test.py +10 -10
- cirq/testing/equals_tester_test.py +19 -17
- cirq/transformers/__init__.py +5 -0
- cirq/transformers/symbolize.py +101 -0
- cirq/transformers/symbolize_test.py +60 -0
- cirq/value/random_state_test.py +3 -3
- cirq/value/timestamp.py +4 -0
- cirq/value/timestamp_test.py +10 -10
- cirq/vis/density_matrix_test.py +17 -17
- cirq/work/collector_test.py +13 -10
- cirq/work/observable_measurement.py +14 -2
- cirq/work/observable_measurement_data.py +3 -3
- cirq/work/observable_measurement_test.py +43 -27
- cirq/work/observable_settings.py +2 -12
- cirq/work/observable_settings_test.py +7 -7
- cirq/work/pauli_sum_collector_test.py +7 -9
- cirq/work/sampler_test.py +25 -22
- {cirq_core-1.6.0.dev20250516060316.dist-info → cirq_core-1.6.0.dev20250517012327.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250516060316.dist-info → cirq_core-1.6.0.dev20250517012327.dist-info}/RECORD +26 -24
- {cirq_core-1.6.0.dev20250516060316.dist-info → cirq_core-1.6.0.dev20250517012327.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250516060316.dist-info → cirq_core-1.6.0.dev20250517012327.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250516060316.dist-info → cirq_core-1.6.0.dev20250517012327.dist-info}/top_level.txt +0 -0
cirq/__init__.py
CHANGED
|
@@ -397,6 +397,7 @@ from cirq.transformers import (
|
|
|
397
397
|
single_qubit_matrix_to_phxz as single_qubit_matrix_to_phxz,
|
|
398
398
|
single_qubit_op_to_framed_phase_form as single_qubit_op_to_framed_phase_form,
|
|
399
399
|
stratified_circuit as stratified_circuit,
|
|
400
|
+
symbolize_single_qubit_gates_by_indexed_tags as symbolize_single_qubit_gates_by_indexed_tags,
|
|
400
401
|
synchronize_terminal_measurements as synchronize_terminal_measurements,
|
|
401
402
|
TRANSFORMER as TRANSFORMER,
|
|
402
403
|
TransformerContext as TransformerContext,
|
cirq/_import_test.py
CHANGED
|
@@ -17,9 +17,9 @@ from __future__ import annotations
|
|
|
17
17
|
from cirq import _import
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def test_lazy_loader():
|
|
20
|
+
def test_lazy_loader() -> None:
|
|
21
21
|
linalg = _import.LazyLoader("linalg", globals(), "scipy.linalg")
|
|
22
|
-
linalg.fun = 1
|
|
22
|
+
linalg.fun = 1 # type: ignore[attr-defined]
|
|
23
23
|
assert linalg._module is None
|
|
24
24
|
assert "linalg" not in linalg.__dict__
|
|
25
25
|
|
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
|
@@ -19,7 +19,7 @@ import sympy
|
|
|
19
19
|
from cirq.interop.quirk.cells.parse import parse_complex, parse_formula, parse_matrix
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def test_parse_matrix():
|
|
22
|
+
def test_parse_matrix() -> None:
|
|
23
23
|
s = np.sqrt(0.5)
|
|
24
24
|
np.testing.assert_allclose(
|
|
25
25
|
parse_matrix('{{√½,√½},{-√½,√½}}'), np.array([[s, s], [-s, s]]), atol=1e-8
|
|
@@ -32,7 +32,7 @@ def test_parse_matrix():
|
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def test_parse_matrix_failures():
|
|
35
|
+
def test_parse_matrix_failures() -> None:
|
|
36
36
|
with pytest.raises(ValueError, match='Not surrounded by {{}}'):
|
|
37
37
|
_ = parse_matrix('1')
|
|
38
38
|
with pytest.raises(ValueError, match='Not surrounded by {{}}'):
|
|
@@ -45,7 +45,7 @@ def test_parse_matrix_failures():
|
|
|
45
45
|
_ = parse_matrix('{{x}}')
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
def test_parse_real_formula():
|
|
48
|
+
def test_parse_real_formula() -> None:
|
|
49
49
|
t = sympy.Symbol('t')
|
|
50
50
|
assert parse_formula('1/2') == 0.5
|
|
51
51
|
assert parse_formula('t*t + ln(t)') == t * t + sympy.ln(t)
|
|
@@ -58,12 +58,12 @@ def test_parse_real_formula():
|
|
|
58
58
|
_ = parse_formula('i')
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
def test_parse_formula_failures():
|
|
61
|
+
def test_parse_formula_failures() -> None:
|
|
62
62
|
with pytest.raises(TypeError, match='formula must be a string'):
|
|
63
|
-
_ = parse_formula(2)
|
|
63
|
+
_ = parse_formula(2) # type: ignore[arg-type]
|
|
64
64
|
|
|
65
65
|
with pytest.raises(TypeError, match='formula must be a string'):
|
|
66
|
-
_ = parse_formula([])
|
|
66
|
+
_ = parse_formula([]) # type: ignore[arg-type]
|
|
67
67
|
|
|
68
68
|
with pytest.raises(ValueError, match='Unrecognized token'):
|
|
69
69
|
_ = parse_formula('5*__**DSA **)SADD')
|
|
@@ -72,7 +72,7 @@ def test_parse_formula_failures():
|
|
|
72
72
|
_ = parse_formula('5*x')
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def test_parse_complex():
|
|
75
|
+
def test_parse_complex() -> None:
|
|
76
76
|
assert parse_complex('0') == 0
|
|
77
77
|
assert parse_complex('1') == 1
|
|
78
78
|
assert parse_complex('i') == 1j
|
|
@@ -84,7 +84,7 @@ def test_parse_complex():
|
|
|
84
84
|
np.testing.assert_allclose(parse_complex('exp 2'), np.e**2, atol=1e-8)
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
def test_parse_complex_raw_cases_from_quirk():
|
|
87
|
+
def test_parse_complex_raw_cases_from_quirk() -> None:
|
|
88
88
|
assert parse_complex("0") == 0
|
|
89
89
|
assert parse_complex("1") == 1
|
|
90
90
|
assert parse_complex("-1") == -1
|
|
@@ -116,7 +116,7 @@ def test_parse_complex_raw_cases_from_quirk():
|
|
|
116
116
|
np.testing.assert_allclose(parse_complex("2 pi"), 2 * np.pi)
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
def test_parse_complex_expression_cases_from_quirk():
|
|
119
|
+
def test_parse_complex_expression_cases_from_quirk() -> None:
|
|
120
120
|
np.testing.assert_allclose(parse_complex("1/3"), 1 / 3)
|
|
121
121
|
np.testing.assert_allclose(parse_complex("2/3/5"), (2 / 3) / 5)
|
|
122
122
|
np.testing.assert_allclose(parse_complex("2/3/5*7/13"), ((((2 / 3) / 5)) * 7) / 13)
|
|
@@ -152,7 +152,7 @@ def test_parse_complex_expression_cases_from_quirk():
|
|
|
152
152
|
np.testing.assert_allclose(parse_complex("cos(acos(0.5))"), 0.5, atol=1e-8)
|
|
153
153
|
|
|
154
154
|
|
|
155
|
-
def test_parse_complex_expression_failures():
|
|
155
|
+
def test_parse_complex_expression_failures() -> None:
|
|
156
156
|
with pytest.raises(ValueError, match='Incomplete expression'):
|
|
157
157
|
_ = parse_formula('(')
|
|
158
158
|
with pytest.raises(ValueError, match=r"unmatched '\)'"):
|
|
@@ -19,7 +19,7 @@ import pytest
|
|
|
19
19
|
from cirq.testing.equals_tester import EqualsTester
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def test_add_equality_group_correct():
|
|
22
|
+
def test_add_equality_group_correct() -> None:
|
|
23
23
|
eq = EqualsTester()
|
|
24
24
|
|
|
25
25
|
eq.add_equality_group(fractions.Fraction(1, 1))
|
|
@@ -39,7 +39,7 @@ def test_add_equality_group_correct():
|
|
|
39
39
|
eq.add_equality_group('unrelated')
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def test_assert_make_equality_group():
|
|
42
|
+
def test_assert_make_equality_group() -> None:
|
|
43
43
|
eq = EqualsTester()
|
|
44
44
|
|
|
45
45
|
with pytest.raises(AssertionError, match="can't be in the same"):
|
|
@@ -57,20 +57,20 @@ def test_assert_make_equality_group():
|
|
|
57
57
|
eq.make_equality_group(lambda: 3)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
def test_add_equality_group_not_equivalent():
|
|
60
|
+
def test_add_equality_group_not_equivalent() -> None:
|
|
61
61
|
eq = EqualsTester()
|
|
62
62
|
with pytest.raises(AssertionError, match="can't be in the same"):
|
|
63
63
|
eq.add_equality_group(1, 2)
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
def test_add_equality_group_not_disjoint():
|
|
66
|
+
def test_add_equality_group_not_disjoint() -> None:
|
|
67
67
|
eq = EqualsTester()
|
|
68
68
|
eq.add_equality_group(1)
|
|
69
69
|
with pytest.raises(AssertionError, match="can't be in different"):
|
|
70
70
|
eq.add_equality_group(1)
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
def test_add_equality_group_bad_hash():
|
|
73
|
+
def test_add_equality_group_bad_hash() -> None:
|
|
74
74
|
class KeyHash:
|
|
75
75
|
def __init__(self, k, h):
|
|
76
76
|
self._k = k
|
|
@@ -94,7 +94,7 @@ def test_add_equality_group_bad_hash():
|
|
|
94
94
|
eq.add_equality_group(KeyHash('c', 2), KeyHash('c', 3))
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
def test_add_equality_group_exception_hash():
|
|
97
|
+
def test_add_equality_group_exception_hash() -> None:
|
|
98
98
|
class FailHash:
|
|
99
99
|
def __hash__(self):
|
|
100
100
|
raise ValueError('injected failure')
|
|
@@ -104,7 +104,7 @@ def test_add_equality_group_exception_hash():
|
|
|
104
104
|
eq.add_equality_group(FailHash())
|
|
105
105
|
|
|
106
106
|
|
|
107
|
-
def test_fails_when_forgot_type_check():
|
|
107
|
+
def test_fails_when_forgot_type_check() -> None:
|
|
108
108
|
eq = EqualsTester()
|
|
109
109
|
|
|
110
110
|
class NoTypeCheckEqualImplementation:
|
|
@@ -124,11 +124,12 @@ def test_fails_when_forgot_type_check():
|
|
|
124
124
|
eq.add_equality_group(NoTypeCheckEqualImplementation())
|
|
125
125
|
|
|
126
126
|
|
|
127
|
-
def test_fails_when_equal_to_everything():
|
|
127
|
+
def test_fails_when_equal_to_everything() -> None:
|
|
128
128
|
eq = EqualsTester()
|
|
129
129
|
|
|
130
130
|
class AllEqual:
|
|
131
|
-
__hash__
|
|
131
|
+
def __hash__(self) -> int:
|
|
132
|
+
return 0
|
|
132
133
|
|
|
133
134
|
def __eq__(self, other):
|
|
134
135
|
return True
|
|
@@ -136,11 +137,12 @@ def test_fails_when_equal_to_everything():
|
|
|
136
137
|
def __ne__(self, other):
|
|
137
138
|
return False
|
|
138
139
|
|
|
140
|
+
assert hash(AllEqual()) == 0
|
|
139
141
|
with pytest.raises(AssertionError, match="can't be in different"):
|
|
140
142
|
eq.add_equality_group(AllEqual())
|
|
141
143
|
|
|
142
144
|
|
|
143
|
-
def test_fails_hash_is_default_and_inconsistent():
|
|
145
|
+
def test_fails_hash_is_default_and_inconsistent() -> None:
|
|
144
146
|
eq = EqualsTester()
|
|
145
147
|
|
|
146
148
|
class DefaultHashImplementation:
|
|
@@ -161,7 +163,7 @@ def test_fails_hash_is_default_and_inconsistent():
|
|
|
161
163
|
eq.make_equality_group(DefaultHashImplementation)
|
|
162
164
|
|
|
163
165
|
|
|
164
|
-
def test_fails_when_ne_is_inconsistent():
|
|
166
|
+
def test_fails_when_ne_is_inconsistent() -> None:
|
|
165
167
|
eq = EqualsTester()
|
|
166
168
|
|
|
167
169
|
class InconsistentNeImplementation:
|
|
@@ -185,7 +187,7 @@ def test_fails_when_ne_is_inconsistent():
|
|
|
185
187
|
eq.make_equality_group(InconsistentNeImplementation)
|
|
186
188
|
|
|
187
189
|
|
|
188
|
-
def test_fails_when_ne_is_inconsistent_due_to_not_implemented():
|
|
190
|
+
def test_fails_when_ne_is_inconsistent_due_to_not_implemented() -> None:
|
|
189
191
|
eq = EqualsTester()
|
|
190
192
|
|
|
191
193
|
class InconsistentNeImplementation:
|
|
@@ -207,7 +209,7 @@ def test_fails_when_ne_is_inconsistent_due_to_not_implemented():
|
|
|
207
209
|
eq.make_equality_group(InconsistentNeImplementation)
|
|
208
210
|
|
|
209
211
|
|
|
210
|
-
def test_fails_when_not_reflexive():
|
|
212
|
+
def test_fails_when_not_reflexive() -> None:
|
|
211
213
|
eq = EqualsTester()
|
|
212
214
|
|
|
213
215
|
class NotReflexiveImplementation:
|
|
@@ -226,7 +228,7 @@ def test_fails_when_not_reflexive():
|
|
|
226
228
|
eq.add_equality_group(NotReflexiveImplementation())
|
|
227
229
|
|
|
228
230
|
|
|
229
|
-
def test_fails_when_not_commutative():
|
|
231
|
+
def test_fails_when_not_commutative() -> None:
|
|
230
232
|
eq = EqualsTester()
|
|
231
233
|
|
|
232
234
|
class NotCommutativeImplementation:
|
|
@@ -248,14 +250,14 @@ def test_fails_when_not_commutative():
|
|
|
248
250
|
eq.add_equality_group(NotCommutativeImplementation(1), NotCommutativeImplementation(0))
|
|
249
251
|
|
|
250
252
|
|
|
251
|
-
def test_works_on_types():
|
|
253
|
+
def test_works_on_types() -> None:
|
|
252
254
|
eq = EqualsTester()
|
|
253
255
|
eq.add_equality_group(object)
|
|
254
256
|
eq.add_equality_group(int)
|
|
255
257
|
eq.add_equality_group(object())
|
|
256
258
|
|
|
257
259
|
|
|
258
|
-
def test_returns_not_implemented_for_other_types():
|
|
260
|
+
def test_returns_not_implemented_for_other_types() -> None:
|
|
259
261
|
# First we demonstrate an example of the problem.
|
|
260
262
|
|
|
261
263
|
# FirstClass is the class that is broken.
|
|
@@ -323,7 +325,7 @@ def test_returns_not_implemented_for_other_types():
|
|
|
323
325
|
eq.add_equality_group(ThirdClass("a"), ThirdClass("a"))
|
|
324
326
|
|
|
325
327
|
|
|
326
|
-
def test_not_implemented_error():
|
|
328
|
+
def test_not_implemented_error() -> None:
|
|
327
329
|
# Common bug is to return NotImplementedError instead of NotImplemented.
|
|
328
330
|
class NotImplementedErrorCase:
|
|
329
331
|
def __init__(self, val):
|
cirq/transformers/__init__.py
CHANGED
|
@@ -135,6 +135,11 @@ from cirq.transformers.transformer_primitives import (
|
|
|
135
135
|
unroll_circuit_op_greedy_frontier as unroll_circuit_op_greedy_frontier,
|
|
136
136
|
)
|
|
137
137
|
|
|
138
|
+
from cirq.transformers.symbolize import (
|
|
139
|
+
SymbolizeTag as SymbolizeTag,
|
|
140
|
+
symbolize_single_qubit_gates_by_indexed_tags as symbolize_single_qubit_gates_by_indexed_tags,
|
|
141
|
+
)
|
|
142
|
+
|
|
138
143
|
from cirq.transformers.gauge_compiling import (
|
|
139
144
|
CZGaugeTransformer as CZGaugeTransformer,
|
|
140
145
|
ConstantGauge as ConstantGauge,
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Copyright 2025 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
|
+
"""Transformers that symbolize operations."""
|
|
16
|
+
|
|
17
|
+
import re
|
|
18
|
+
from typing import Hashable, Optional, TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
import attrs
|
|
21
|
+
import sympy
|
|
22
|
+
from attrs import validators
|
|
23
|
+
|
|
24
|
+
from cirq import ops
|
|
25
|
+
from cirq.transformers import transformer_api, transformer_primitives
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
import cirq
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@attrs.frozen
|
|
32
|
+
class SymbolizeTag:
|
|
33
|
+
prefix: str = attrs.field(
|
|
34
|
+
validator=validators.and_(validators.instance_of(str), validators.min_len(1))
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@transformer_api.transformer
|
|
39
|
+
def symbolize_single_qubit_gates_by_indexed_tags(
|
|
40
|
+
circuit: 'cirq.AbstractCircuit',
|
|
41
|
+
*,
|
|
42
|
+
context: Optional['cirq.TransformerContext'] = None,
|
|
43
|
+
symbolize_tag: SymbolizeTag = SymbolizeTag(prefix="TO-PHXZ"),
|
|
44
|
+
) -> 'cirq.Circuit':
|
|
45
|
+
"""Symbolizes single qubit operations by indexed tags prefixed by symbolize_tag.prefix.
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
>>> from cirq import transformers
|
|
49
|
+
>>> q0, q1 = cirq.LineQubit.range(2)
|
|
50
|
+
>>> c = cirq.Circuit(
|
|
51
|
+
... cirq.X(q0).with_tags("phxz_0"),
|
|
52
|
+
... cirq.CZ(q0,q1),
|
|
53
|
+
... cirq.Y(q0).with_tags("phxz_1"),
|
|
54
|
+
... cirq.X(q0))
|
|
55
|
+
>>> print(c)
|
|
56
|
+
0: ───X[phxz_0]───@───Y[phxz_1]───X───
|
|
57
|
+
│
|
|
58
|
+
1: ───────────────@───────────────────
|
|
59
|
+
>>> new_circuit = cirq.symbolize_single_qubit_gates_by_indexed_tags(
|
|
60
|
+
... c, symbolize_tag=transformers.SymbolizeTag(prefix="phxz"))
|
|
61
|
+
>>> print(new_circuit)
|
|
62
|
+
0: ───PhXZ(a=a0,x=x0,z=z0)───@───PhXZ(a=a1,x=x1,z=z1)───X───
|
|
63
|
+
│
|
|
64
|
+
1: ──────────────────────────@──────────────────────────────
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
circuit: Input circuit to apply the transformations on. The input circuit is not mutated.
|
|
68
|
+
context: `cirq.TransformerContext` storing common configurable options for transformers.
|
|
69
|
+
symbolize_tag: The tag info used to symbolize the phxz gate. Prefix is required.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Copy of the transformed input circuit.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def _map_func(op: 'cirq.Operation', _):
|
|
76
|
+
"""Maps an op with tag `{tag_prefix}_i` to a symbolzied `PhasedXZGate(xi,zi,ai)`."""
|
|
77
|
+
tags: set[Hashable] = set(op.tags)
|
|
78
|
+
tag_id: None | int = None
|
|
79
|
+
for tag in tags:
|
|
80
|
+
if re.fullmatch(f"{symbolize_tag.prefix}_\\d+", str(tag)):
|
|
81
|
+
if tag_id is None:
|
|
82
|
+
tag_id = int(str(tag).rsplit("_", maxsplit=-1)[-1])
|
|
83
|
+
else:
|
|
84
|
+
raise ValueError(f"Multiple tags are prefixed with {symbolize_tag.prefix}.")
|
|
85
|
+
if tag_id is None:
|
|
86
|
+
return op
|
|
87
|
+
tags.remove(f"{symbolize_tag.prefix}_{tag_id}")
|
|
88
|
+
phxz_params = {
|
|
89
|
+
"x_exponent": sympy.Symbol(f"x{tag_id}"),
|
|
90
|
+
"z_exponent": sympy.Symbol(f"z{tag_id}"),
|
|
91
|
+
"axis_phase_exponent": sympy.Symbol(f"a{tag_id}"),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return ops.PhasedXZGate(**phxz_params).on(*op.qubits).with_tags(*tags)
|
|
95
|
+
|
|
96
|
+
return transformer_primitives.map_operations(
|
|
97
|
+
circuit.freeze(),
|
|
98
|
+
_map_func,
|
|
99
|
+
deep=context.deep if context else False,
|
|
100
|
+
tags_to_ignore=context.tags_to_ignore if context else [],
|
|
101
|
+
).unfreeze(copy=False)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Copyright 2025 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 pytest
|
|
16
|
+
import sympy
|
|
17
|
+
|
|
18
|
+
import cirq
|
|
19
|
+
from cirq.transformers.symbolize import SymbolizeTag
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_symbolize_single_qubit_gates_by_indexed_tags_success():
|
|
23
|
+
q = cirq.NamedQubit("a")
|
|
24
|
+
input_circuit = cirq.Circuit(
|
|
25
|
+
cirq.X(q).with_tags("phxz_1"), cirq.Y(q).with_tags("tag1"), cirq.Z(q).with_tags("phxz_0")
|
|
26
|
+
)
|
|
27
|
+
output_circuit = cirq.symbolize_single_qubit_gates_by_indexed_tags(
|
|
28
|
+
input_circuit, symbolize_tag=SymbolizeTag(prefix="phxz")
|
|
29
|
+
)
|
|
30
|
+
cirq.testing.assert_same_circuits(
|
|
31
|
+
output_circuit,
|
|
32
|
+
cirq.Circuit(
|
|
33
|
+
cirq.PhasedXZGate(
|
|
34
|
+
x_exponent=sympy.Symbol("x1"),
|
|
35
|
+
z_exponent=sympy.Symbol("z1"),
|
|
36
|
+
axis_phase_exponent=sympy.Symbol("a1"),
|
|
37
|
+
).on(q),
|
|
38
|
+
cirq.Y(q).with_tags("tag1"),
|
|
39
|
+
cirq.PhasedXZGate(
|
|
40
|
+
x_exponent=sympy.Symbol("x0"),
|
|
41
|
+
z_exponent=sympy.Symbol("z0"),
|
|
42
|
+
axis_phase_exponent=sympy.Symbol("a0"),
|
|
43
|
+
).on(q),
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_symbolize_single_qubit_gates_by_indexed_tags_multiple_tags():
|
|
49
|
+
q = cirq.NamedQubit("a")
|
|
50
|
+
input_circuit = cirq.Circuit(cirq.X(q).with_tags("TO-PHXZ_0", "TO-PHXZ_2"))
|
|
51
|
+
|
|
52
|
+
with pytest.raises(ValueError, match="Multiple tags are prefixed with TO-PHXZ."):
|
|
53
|
+
cirq.symbolize_single_qubit_gates_by_indexed_tags(input_circuit)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_symbolize_tag_invalid_prefix():
|
|
57
|
+
with pytest.raises(ValueError, match="Length of 'prefix' must be >= 1: 0"):
|
|
58
|
+
SymbolizeTag(prefix="")
|
|
59
|
+
with pytest.raises(TypeError, match="'prefix' must be <class 'str'>"):
|
|
60
|
+
SymbolizeTag(prefix=[1])
|
cirq/value/random_state_test.py
CHANGED
|
@@ -17,7 +17,7 @@ import numpy as np
|
|
|
17
17
|
import cirq
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def test_parse_random_state():
|
|
20
|
+
def test_parse_random_state() -> None:
|
|
21
21
|
global_state = np.random.get_state()
|
|
22
22
|
|
|
23
23
|
def rand(prng):
|
|
@@ -34,11 +34,11 @@ def test_parse_random_state():
|
|
|
34
34
|
eq.add_equality_group(*vals)
|
|
35
35
|
|
|
36
36
|
seed = np.random.randint(2**31)
|
|
37
|
-
|
|
37
|
+
prngs1 = [
|
|
38
38
|
np.random.RandomState(seed),
|
|
39
39
|
cirq.value.parse_random_state(np.random.RandomState(seed)),
|
|
40
40
|
cirq.value.parse_random_state(seed),
|
|
41
41
|
]
|
|
42
|
-
vals = [prng.rand() for prng in
|
|
42
|
+
vals = [prng.rand() for prng in prngs1]
|
|
43
43
|
eq = cirq.testing.EqualsTester()
|
|
44
44
|
eq.add_equality_group(*vals)
|
cirq/value/timestamp.py
CHANGED
|
@@ -64,6 +64,10 @@ class Timestamp:
|
|
|
64
64
|
def __sub__(self, other: Duration) -> 'Timestamp':
|
|
65
65
|
pass
|
|
66
66
|
|
|
67
|
+
@overload
|
|
68
|
+
def __sub__(self, other: timedelta) -> 'Timestamp':
|
|
69
|
+
pass
|
|
70
|
+
|
|
67
71
|
def __sub__(self, other):
|
|
68
72
|
if isinstance(other, Duration):
|
|
69
73
|
return Timestamp(picos=self._picos - other.total_picos())
|
cirq/value/timestamp_test.py
CHANGED
|
@@ -20,7 +20,7 @@ import cirq
|
|
|
20
20
|
from cirq import Duration, Timestamp
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def test_init():
|
|
23
|
+
def test_init() -> None:
|
|
24
24
|
assert Timestamp().raw_picos() == 0
|
|
25
25
|
assert Timestamp(picos=513).raw_picos() == 513
|
|
26
26
|
assert Timestamp(picos=-5).raw_picos() == -5
|
|
@@ -33,13 +33,13 @@ def test_init():
|
|
|
33
33
|
assert isinstance(Timestamp(nanos=1.0).raw_picos(), float)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def test_str():
|
|
36
|
+
def test_str() -> None:
|
|
37
37
|
assert str(Timestamp(picos=1000, nanos=1000)) == 't=1001000'
|
|
38
38
|
assert str(Timestamp(nanos=5.0)) == 't=5000.0'
|
|
39
39
|
assert str(Timestamp(picos=-100)) == 't=-100'
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def test_repr():
|
|
42
|
+
def test_repr() -> None:
|
|
43
43
|
a = Timestamp(picos=1000, nanos=1000)
|
|
44
44
|
cirq.testing.assert_equivalent_repr(a)
|
|
45
45
|
b = Timestamp(nanos=5.0)
|
|
@@ -48,14 +48,14 @@ def test_repr():
|
|
|
48
48
|
cirq.testing.assert_equivalent_repr(c)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def test_eq():
|
|
51
|
+
def test_eq() -> None:
|
|
52
52
|
eq = cirq.testing.EqualsTester()
|
|
53
53
|
eq.add_equality_group(Timestamp(), Timestamp(picos=0), Timestamp(nanos=0.0))
|
|
54
54
|
eq.add_equality_group(Timestamp(picos=1000), Timestamp(nanos=1))
|
|
55
55
|
eq.make_equality_group(lambda: Timestamp(picos=-1))
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
def test_cmp():
|
|
58
|
+
def test_cmp() -> None:
|
|
59
59
|
ordered_groups = [
|
|
60
60
|
Timestamp(picos=-1),
|
|
61
61
|
Timestamp(),
|
|
@@ -81,7 +81,7 @@ def test_cmp():
|
|
|
81
81
|
assert Timestamp() != Duration()
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
def test_cmp_vs_other_type():
|
|
84
|
+
def test_cmp_vs_other_type() -> None:
|
|
85
85
|
with pytest.raises(TypeError):
|
|
86
86
|
_ = Timestamp() < Duration()
|
|
87
87
|
with pytest.raises(TypeError):
|
|
@@ -94,7 +94,7 @@ def test_cmp_vs_other_type():
|
|
|
94
94
|
_ = Timestamp() > 0
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
def test_add():
|
|
97
|
+
def test_add() -> None:
|
|
98
98
|
assert Timestamp(picos=1) + Duration(picos=2) == Timestamp(picos=3)
|
|
99
99
|
assert Duration(picos=3) + Timestamp(picos=-5) == Timestamp(picos=-2)
|
|
100
100
|
|
|
@@ -109,7 +109,7 @@ def test_add():
|
|
|
109
109
|
_ = Timestamp() + 1
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
def test_sub():
|
|
112
|
+
def test_sub() -> None:
|
|
113
113
|
assert Timestamp() - Timestamp() == Duration()
|
|
114
114
|
assert Timestamp(picos=1) - Timestamp(picos=2) == Duration(picos=-1)
|
|
115
115
|
assert Timestamp(picos=5) - Duration(picos=2) == Timestamp(picos=3)
|
|
@@ -118,6 +118,6 @@ def test_sub():
|
|
|
118
118
|
with pytest.raises(TypeError):
|
|
119
119
|
_ = Duration() - Timestamp()
|
|
120
120
|
with pytest.raises(TypeError):
|
|
121
|
-
_ = 1 - Timestamp()
|
|
121
|
+
_ = 1 - Timestamp() # type: ignore[operator]
|
|
122
122
|
with pytest.raises(TypeError):
|
|
123
|
-
_ = Timestamp() - 1
|
|
123
|
+
_ = Timestamp() - 1 # type: ignore[operator]
|
cirq/vis/density_matrix_test.py
CHANGED
|
@@ -24,7 +24,7 @@ from cirq.vis.density_matrix import _plot_element_of_density_matrix, plot_densit
|
|
|
24
24
|
@pytest.mark.usefixtures('closefigures')
|
|
25
25
|
@pytest.mark.parametrize('show_text', [True, False])
|
|
26
26
|
@pytest.mark.parametrize('size', [2, 4, 8, 16])
|
|
27
|
-
def test_density_matrix_plotter(size, show_text):
|
|
27
|
+
def test_density_matrix_plotter(size, show_text) -> None:
|
|
28
28
|
matrix = cirq.testing.random_density_matrix(size)
|
|
29
29
|
# Check that the title shows back up
|
|
30
30
|
ax = plot_density_matrix(matrix, show_text=show_text, title='Test Density Matrix Plot')
|
|
@@ -48,16 +48,16 @@ def test_density_matrix_plotter(size, show_text):
|
|
|
48
48
|
@pytest.mark.usefixtures('closefigures')
|
|
49
49
|
@pytest.mark.parametrize('show_text', [True, False])
|
|
50
50
|
@pytest.mark.parametrize('size', [2, 4, 8, 16])
|
|
51
|
-
def test_density_matrix_circle_rectangle_sizes(size, show_text):
|
|
51
|
+
def test_density_matrix_circle_rectangle_sizes(size, show_text) -> None:
|
|
52
52
|
matrix = cirq.testing.random_density_matrix(size)
|
|
53
53
|
ax = plot_density_matrix(matrix, show_text=show_text, title='Test Density Matrix Plot')
|
|
54
54
|
# Check that the radius of all the circles in the matrix is correct
|
|
55
|
-
|
|
56
|
-
mean_radius = np.mean([c.radius for c in
|
|
55
|
+
circle_list = [c for c in ax.get_children() if isinstance(c, patches.Circle)]
|
|
56
|
+
mean_radius = np.mean([c.radius for c in circle_list if c.fill])
|
|
57
57
|
mean_value = np.mean(np.abs(matrix))
|
|
58
|
-
circles = np.array(
|
|
59
|
-
(
|
|
60
|
-
)
|
|
58
|
+
circles = np.array(
|
|
59
|
+
sorted(circle_list, key=lambda x: (x.fill, x.center[0], -x.center[1]))
|
|
60
|
+
).reshape((2, size, size))
|
|
61
61
|
for i in range(size):
|
|
62
62
|
for j in range(size):
|
|
63
63
|
assert np.isclose(
|
|
@@ -65,15 +65,15 @@ def test_density_matrix_circle_rectangle_sizes(size, show_text):
|
|
|
65
65
|
)
|
|
66
66
|
|
|
67
67
|
# Check that all the rectangles are of the right height, and only on the diagonal elements
|
|
68
|
-
|
|
68
|
+
rect_list = [
|
|
69
69
|
r
|
|
70
70
|
for r in ax.get_children()
|
|
71
71
|
if isinstance(r, patches.Rectangle) and r.get_alpha() is not None
|
|
72
72
|
]
|
|
73
|
-
assert len(
|
|
74
|
-
mean_size = np.mean([r.get_height() for r in
|
|
73
|
+
assert len(rect_list) == size
|
|
74
|
+
mean_size = np.mean([r.get_height() for r in rect_list])
|
|
75
75
|
mean_value = np.trace(np.abs(matrix)) / size
|
|
76
|
-
rects = np.array(sorted(
|
|
76
|
+
rects = np.array(sorted(rect_list, key=lambda x: x.get_x()))
|
|
77
77
|
for i in range(size):
|
|
78
78
|
# Ensuring that the rectangle is the right height
|
|
79
79
|
assert np.isclose(np.abs(matrix[i, i]) * mean_size / mean_value, rects[i].get_height())
|
|
@@ -90,7 +90,7 @@ def test_density_matrix_circle_rectangle_sizes(size, show_text):
|
|
|
90
90
|
@pytest.mark.usefixtures('closefigures')
|
|
91
91
|
@pytest.mark.parametrize('show_text', [True, False])
|
|
92
92
|
@pytest.mark.parametrize('size', [2, 4, 8, 16])
|
|
93
|
-
def test_density_matrix_sizes_upper_bounds(size, show_text):
|
|
93
|
+
def test_density_matrix_sizes_upper_bounds(size, show_text) -> None:
|
|
94
94
|
matrix = cirq.testing.random_density_matrix(size)
|
|
95
95
|
ax = plot_density_matrix(matrix, show_text=show_text, title='Test Density Matrix Plot')
|
|
96
96
|
|
|
@@ -113,7 +113,7 @@ def test_density_matrix_sizes_upper_bounds(size, show_text):
|
|
|
113
113
|
@pytest.mark.usefixtures('closefigures')
|
|
114
114
|
@pytest.mark.parametrize('show_rect', [True, False])
|
|
115
115
|
@pytest.mark.parametrize('value', [0.0, 1.0, 0.5 + 0.3j, 0.2 + 0.1j, 0.5 + 0.5j])
|
|
116
|
-
def test_density_element_plot(value, show_rect):
|
|
116
|
+
def test_density_element_plot(value, show_rect) -> None:
|
|
117
117
|
_, ax = plt.subplots(figsize=(10, 10))
|
|
118
118
|
_plot_element_of_density_matrix(
|
|
119
119
|
ax, 0, 0, np.abs(value), np.angle(value), show_rect=False, show_text=False
|
|
@@ -122,9 +122,9 @@ def test_density_element_plot(value, show_rect):
|
|
|
122
122
|
plotted_lines = [c for c in ax.get_children() if isinstance(c, lines.Line2D)]
|
|
123
123
|
assert len(plotted_lines) == 1
|
|
124
124
|
line_position = plotted_lines[0].get_xydata()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)
|
|
125
|
+
numerator = line_position[1, 1] - line_position[0, 1] # type: ignore
|
|
126
|
+
denumerator = line_position[1, 0] - line_position[0, 0] # type: ignore
|
|
127
|
+
angle = np.arctan(numerator / denumerator)
|
|
128
128
|
assert np.isclose(np.angle(value), angle)
|
|
129
129
|
# Check if the circles are the right size ratio, given the value of the element
|
|
130
130
|
circles_in = [c for c in ax.get_children() if isinstance(c, patches.Circle) and c.fill]
|
|
@@ -151,6 +151,6 @@ def test_density_element_plot(value, show_rect):
|
|
|
151
151
|
np.random.random((4, 8)) * np.exp(np.random.random((4, 8)) * 2 * np.pi * 1j),
|
|
152
152
|
],
|
|
153
153
|
)
|
|
154
|
-
def test_density_matrix_type_error(matrix):
|
|
154
|
+
def test_density_matrix_type_error(matrix) -> None:
|
|
155
155
|
with pytest.raises(ValueError, match="Incorrect shape for density matrix:*"):
|
|
156
156
|
plot_density_matrix(matrix)
|