Skip to content

Commit 394e56f

Browse files
Merge remote-tracking branch 'upstream/master' into v13_flush
2 parents 8b6d53c + 954a7b6 commit 394e56f

29 files changed

+224
-21
lines changed

cirq-aqt/cirq_aqt/__init__.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
"""Types and methods related to the AQT ion trap device"""
16+
17+
from cirq_aqt._version import (
18+
__version__,
19+
)
20+
1521
from cirq_aqt.aqt_sampler import AQTSampler, AQTSamplerLocalSimulator
1622
from cirq_aqt.aqt_device import AQTSimulator
17-
18-
"""Types and methods related to the AQT ion trap device"""

cirq-aqt/cirq_aqt/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414

1515
"""Define version number here, read it from setup.py automatically"""
1616

17-
__version__ = "0.13.0.dev"
17+
__version__ = "0.14.0.dev"

cirq-aqt/cirq_aqt/_version_test.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import cirq_aqt
2+
3+
4+
def test_version():
5+
assert cirq_aqt.__version__ == "0.14.0.dev"

cirq-core/cirq/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929
'of cirq (e.g. "python -m pip install cirq==0.5.*")'
3030
)
3131

32-
__version__ = "0.13.0.dev"
32+
__version__ = "0.14.0.dev"

cirq-core/cirq/_version_test.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import cirq
2+
3+
4+
def test_version():
5+
assert cirq.__version__ == "0.14.0.dev"

cirq-core/cirq/contrib/qcircuit/qcircuit_diagram_info.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,8 @@ def multigate_qcircuit_diagram_info(
9898
assert args.qubit_map is not None
9999
assert args.known_qubits is not None
100100
symbols = tuple(box if (args.qubit_map[q] == min_index) else ghost for q in args.known_qubits)
101-
return protocols.CircuitDiagramInfo(
102-
symbols, exponent=1 if info is None else info.exponent, connected=False
103-
)
101+
# Force exponent=1 to defer to exponent formatting given above.
102+
return protocols.CircuitDiagramInfo(symbols, connected=False)
104103

105104

106105
def fallback_qcircuit_diagram_info(

cirq-core/cirq/contrib/qcircuit/qcircuit_diagram_info_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def test_get_qcircuit_diagram_info():
3232
actual_info = ccq.get_qcircuit_diagram_info(op, args)
3333
name = r'{\text{SWAP}^{0.5}}'
3434
expected_info = cirq.CircuitDiagramInfo(
35-
(r'\multigate{1}' + name, r'\ghost' + name), exponent=0.5, connected=False
35+
(r'\multigate{1}' + name, r'\ghost' + name), exponent=1, connected=False
3636
)
3737
assert actual_info == expected_info
3838

cirq-core/cirq/contrib/qcircuit/qcircuit_test.py

+14
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,17 @@ def test_two_cx_diagram():
155155
\\
156156
}""".strip()
157157
assert_has_qcircuit_diagram(circuit, expected_diagram)
158+
159+
160+
def test_sqrt_iswap_diagram():
161+
# test for proper rendering of ISWAP^{0.5}
162+
q0, q1 = cirq.LineQubit.range(2)
163+
circuit = cirq.Circuit(cirq.ISWAP(q0, q1) ** 0.5)
164+
expected_diagram = r"""
165+
\Qcircuit @R=1em @C=0.75em {
166+
\\
167+
&\lstick{\text{0}}& \qw&\multigate{1}{\text{ISWAP}^{0.5}} \qw&\qw\\
168+
&\lstick{\text{1}}& \qw&\ghost{\text{ISWAP}^{0.5}} \qw&\qw\\
169+
\\
170+
}""".strip()
171+
assert_has_qcircuit_diagram(circuit, expected_diagram)

cirq-core/cirq/qis/channels.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def kraus_to_superoperator(kraus_operators: Sequence[np.ndarray]) -> np.ndarray:
153153
return m
154154

155155

156-
def superoperator_to_kraus(superoperator: np.ndarray) -> Sequence[np.ndarray]:
156+
def superoperator_to_kraus(superoperator: np.ndarray, atol: float = 1e-10) -> Sequence[np.ndarray]:
157157
r"""Returns a Kraus representation of a channel specified via the superoperator matrix.
158158
159159
Quantum channel E: L(H1) -> L(H2) may be described by a collection of operators A_i, called
@@ -180,14 +180,16 @@ def superoperator_to_kraus(superoperator: np.ndarray) -> Sequence[np.ndarray]:
180180
181181
Args:
182182
superoperator: Superoperator matrix specifying a quantum channel.
183+
atol: Tolerance used to check which Kraus operators to omit.
183184
184185
Returns:
185186
Sequence of Kraus operators of the channel specified by superoperator.
187+
Kraus operators with Frobenius norm smaller than atol are omitted.
186188
187189
Raises:
188190
ValueError: If superoperator is not a valid superoperator matrix.
189191
"""
190-
return choi_to_kraus(superoperator_to_choi(superoperator))
192+
return choi_to_kraus(superoperator_to_choi(superoperator), atol=atol)
191193

192194

193195
def choi_to_superoperator(choi: np.ndarray) -> np.ndarray:

cirq-core/cirq/qis/channels_test.py

+14
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,13 @@ def test_choi_to_kraus_inverse_of_kraus_to_choi(choi):
229229
assert np.allclose(recovered_choi, choi)
230230

231231

232+
def test_choi_to_kraus_atol():
233+
"""Verifies that insignificant Kraus operators are omitted."""
234+
choi = cirq.kraus_to_choi(cirq.kraus(cirq.phase_damp(1e-6)))
235+
assert len(cirq.choi_to_kraus(choi, atol=1e-2)) == 1
236+
assert len(cirq.choi_to_kraus(choi, atol=1e-4)) == 2
237+
238+
232239
@pytest.mark.parametrize(
233240
'channel',
234241
(
@@ -340,6 +347,13 @@ def test_superoperator_to_kraus_inverse_of_kraus_to_superoperator(superoperator)
340347
assert np.allclose(recovered_superoperator, superoperator)
341348

342349

350+
def test_superoperator_to_kraus_atol():
351+
"""Verifies that insignificant Kraus operators are omitted."""
352+
superop = cirq.kraus_to_superoperator(cirq.kraus(cirq.phase_damp(1e-6)))
353+
assert len(cirq.superoperator_to_kraus(superop, atol=1e-2)) == 1
354+
assert len(cirq.superoperator_to_kraus(superop, atol=1e-4)) == 2
355+
356+
343357
@pytest.mark.parametrize(
344358
'choi, error',
345359
(

cirq-google/cirq_google/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
from cirq_google import api
1818

19+
from cirq_google._version import (
20+
__version__,
21+
)
22+
1923
from cirq_google.calibration import (
2024
ALL_ANGLES_FLOQUET_PHASED_FSIM_CHARACTERIZATION,
2125
CircuitWithCalibration,
@@ -129,6 +133,7 @@
129133
ExecutableResult,
130134
ExecutableGroupResult,
131135
QuantumRuntimeConfiguration,
136+
execute,
132137
)
133138

134139
from cirq_google import experimental

cirq-google/cirq_google/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929
'of cirq (e.g. "python -m pip install cirq==0.5.*")'
3030
)
3131

32-
__version__ = "0.13.0.dev"
32+
__version__ = "0.14.0.dev"
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import cirq_google
2+
3+
4+
def test_version():
5+
assert cirq_google.__version__ == "0.14.0.dev"

cirq-google/cirq_google/workflow/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@
1212
ExecutableResult,
1313
ExecutableGroupResult,
1414
QuantumRuntimeConfiguration,
15+
execute,
1516
)

cirq-google/cirq_google/workflow/quantum_executable.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
import abc
1818
import dataclasses
1919
from dataclasses import dataclass
20-
from typing import Union, Tuple, Optional, Sequence, cast, Iterable, Dict, Any, List
20+
from typing import Union, Tuple, Optional, Sequence, cast, Dict, Any, List, Iterator
2121

22-
from cirq import _compat, study
2322
import cirq
23+
from cirq import _compat, study
2424

2525

2626
class ExecutableSpec(metaclass=abc.ABCMeta):
@@ -232,7 +232,7 @@ def __init__(
232232
def __len__(self) -> int:
233233
return len(self.executables)
234234

235-
def __iter__(self) -> Iterable[QuantumExecutable]:
235+
def __iter__(self) -> Iterator[QuantumExecutable]:
236236
yield from self.executables
237237

238238
def __str__(self) -> str:

cirq-google/cirq_google/workflow/quantum_runtime.py

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

15-
"""Runtime information dataclasses that accompany execution of executables."""
15+
"""Runtime information dataclasses and execution of executables."""
1616

1717
import dataclasses
18+
import os
19+
import uuid
1820
from typing import Any, Dict, Optional, List
1921

2022
import cirq
@@ -23,6 +25,7 @@
2325
from cirq_google.workflow._abstract_engine_processor_shim import AbstractEngineProcessorShim
2426
from cirq_google.workflow.quantum_executable import (
2527
ExecutableSpec,
28+
QuantumExecutableGroup,
2629
)
2730

2831

@@ -133,3 +136,79 @@ def _json_dict_(self) -> Dict[str, Any]:
133136

134137
def __repr__(self) -> str:
135138
return _compat.dataclass_repr(self, namespace='cirq_google')
139+
140+
141+
def execute(
142+
rt_config: QuantumRuntimeConfiguration,
143+
executable_group: QuantumExecutableGroup,
144+
base_data_dir: str = ".",
145+
) -> ExecutableGroupResult:
146+
"""Execute a `cg.QuantumExecutableGroup` according to a `cg.QuantumRuntimeConfiguration`.
147+
148+
Args:
149+
rt_config: The `cg.QuantumRuntimeConfiguration` specifying how to execute
150+
`executable_group`.
151+
executable_group: The `cg.QuantumExecutableGroup` containing the executables to execute.
152+
base_data_dir: A filesystem path to write data. We write
153+
"{base_data_dir}/{run_id}/ExecutableGroupResult.json.gz"
154+
containing the `cg.ExecutableGroupResult` as well as one file
155+
"{base_data_dir}/{run_id}/ExecutableResult.{i}.json.gz" per `cg.ExecutableResult` as
156+
each executable result becomes available.
157+
158+
Returns:
159+
The `cg.ExecutableGroupResult` containing all data and metadata for an execution.
160+
161+
Raises:
162+
NotImplementedError: If an executable uses the `params` field or anything other than
163+
a BitstringsMeasurement measurement field.
164+
ValueError: If `base_data_dir` is not a valid directory.
165+
"""
166+
# run_id defaults logic.
167+
if rt_config.run_id is None:
168+
run_id = str(uuid.uuid4())
169+
else:
170+
run_id = rt_config.run_id
171+
172+
# base_data_dir handling.
173+
if not base_data_dir:
174+
# coverage: ignore
175+
raise ValueError("Please provide a non-empty `base_data_dir`.")
176+
177+
os.makedirs(f'{base_data_dir}/{run_id}', exist_ok=False)
178+
179+
# Results object that we will fill in in the main loop.
180+
exegroup_result = ExecutableGroupResult(
181+
runtime_configuration=rt_config,
182+
shared_runtime_info=SharedRuntimeInfo(run_id=run_id),
183+
executable_results=list(),
184+
)
185+
cirq.to_json_gzip(exegroup_result, f'{base_data_dir}/{run_id}/ExecutableGroupResult.json.gz')
186+
187+
# Loop over executables.
188+
sampler = rt_config.processor.get_sampler()
189+
n_executables = len(executable_group)
190+
print()
191+
for i, exe in enumerate(executable_group):
192+
runtime_info = RuntimeInfo(execution_index=i)
193+
194+
if exe.params != tuple():
195+
raise NotImplementedError("Circuit params are not yet supported.")
196+
197+
circuit = exe.circuit
198+
199+
if not hasattr(exe.measurement, 'n_repetitions'):
200+
raise NotImplementedError("Only `BitstringsMeasurement` are supported.")
201+
202+
sampler_run_result = sampler.run(circuit, repetitions=exe.measurement.n_repetitions)
203+
204+
exe_result = ExecutableResult(
205+
spec=exe.spec,
206+
runtime_info=runtime_info,
207+
raw_data=sampler_run_result,
208+
)
209+
cirq.to_json_gzip(exe_result, f'{base_data_dir}/{run_id}/ExecutableResult.{i}.json.gz')
210+
exegroup_result.executable_results.append(exe_result)
211+
print(f'\r{i+1} / {n_executables}', end='', flush=True)
212+
print()
213+
214+
return exegroup_result

cirq-google/cirq_google/workflow/quantum_runtime_test.py

+35-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
import glob
15+
import re
16+
import uuid
1417
from dataclasses import dataclass
18+
from typing import List
19+
20+
import numpy as np
21+
import pytest
1522

1623
import cirq
1724
import cirq_google as cg
18-
import numpy as np
1925
from cirq_google.workflow._abstract_engine_processor_shim import AbstractEngineProcessorShim
20-
from cirq_google.workflow.quantum_executable_test import _get_example_spec
26+
from cirq_google.workflow.quantum_executable_test import _get_quantum_executables, _get_example_spec
2127

2228

2329
@dataclass
@@ -120,3 +126,30 @@ def test_executable_group_result(tmpdir):
120126
cg_assert_equivalent_repr(egr)
121127
assert len(egr.executable_results) == 3
122128
_assert_json_roundtrip(egr, tmpdir)
129+
130+
131+
@pytest.mark.parametrize('run_id', ['unit_test_runid', None])
132+
def test_execute(tmpdir, run_id):
133+
rt_config = cg.QuantumRuntimeConfiguration(processor=_MockEngineProcessor(), run_id=run_id)
134+
executable_group = cg.QuantumExecutableGroup(_get_quantum_executables())
135+
returned_exegroup_result = cg.execute(
136+
rt_config=rt_config, executable_group=executable_group, base_data_dir=tmpdir
137+
)
138+
actual_run_id = returned_exegroup_result.shared_runtime_info.run_id
139+
if run_id is not None:
140+
assert run_id == actual_run_id
141+
else:
142+
assert isinstance(uuid.UUID(actual_run_id), uuid.UUID)
143+
fns = glob.glob(f'{tmpdir}/{actual_run_id}/ExecutableGroupResult.json.gz')
144+
assert len(fns) == 1
145+
exegroup_result: cg.ExecutableGroupResult = _cg_read_json_gzip(fns[0])
146+
147+
fns = glob.glob(f'{tmpdir}/{actual_run_id}/ExecutableResult.*.json.gz')
148+
fns = sorted(
149+
fns, key=lambda s: int(re.search(r'ExecutableResult\.(\d+)\.json\.gz$', s).group(1))
150+
)
151+
assert len(fns) == 3
152+
exe_results: List[cg.ExecutableResult] = [_cg_read_json_gzip(fn) for fn in fns]
153+
154+
exegroup_result.executable_results = exe_results
155+
assert returned_exegroup_result == exegroup_result

cirq-ionq/cirq_ionq/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from cirq_ionq._version import (
16+
__version__,
17+
)
18+
1519
from cirq_ionq.calibration import (
1620
Calibration,
1721
)

cirq-ionq/cirq_ionq/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414

1515
"""Define version number here, read it from setup.py automatically"""
1616

17-
__version__ = "0.13.0.dev"
17+
__version__ = "0.14.0.dev"

cirq-ionq/cirq_ionq/_version_test.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import cirq_ionq
2+
3+
4+
def test_version():
5+
assert cirq_ionq.__version__ == "0.14.0.dev"

cirq-pasqal/cirq_pasqal/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
"""Devices, qubits, and sampler for Pasqal's neutral atom device."""
1616

17+
from cirq_pasqal._version import (
18+
__version__,
19+
)
20+
1721
from cirq_pasqal.pasqal_qubits import (
1822
ThreeDQubit,
1923
TwoDQubit,

cirq-pasqal/cirq_pasqal/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414

1515
"""Define version number here, read it from setup.py automatically"""
1616

17-
__version__ = "0.13.0.dev"
17+
__version__ = "0.14.0.dev"
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import cirq_pasqal
2+
3+
4+
def test_version():
5+
assert cirq_pasqal.__version__ == "0.14.0.dev"

0 commit comments

Comments
 (0)