Skip to content

Commit 010012f

Browse files
Merge branch 'main' into update_serialization
2 parents c144d8b + 4513892 commit 010012f

File tree

9 files changed

+141
-39
lines changed

9 files changed

+141
-39
lines changed

Diff for: cirq-core/cirq/circuits/qasm_output.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,11 @@ def output(text):
293293
output(f'creg {meas_id}[{len(meas.qubits)}];\n')
294294
else:
295295
output(f'creg {meas_id}[{len(meas.qubits)}]; // Measurement: {comment}\n')
296-
output_line_gap(2)
296+
# In OpenQASM 2.0, the transformation of global phase gates is ignored.
297+
# Therefore, no newline is created when the operations contained in
298+
# a circuit consist only of global phase gates.
299+
if any(not isinstance(op.gate, ops.GlobalPhaseGate) for op in self.operations):
300+
output_line_gap(2)
297301

298302
# Operations
299303
self._write_operations(self.operations, output, output_line_gap)

Diff for: cirq-core/cirq/circuits/qasm_output_test.py

+13
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,19 @@ def test_h_gate_with_parameter():
191191
)
192192

193193

194+
def test_qasm_global_pahse():
195+
output = cirq.QasmOutput((cirq.global_phase_operation(np.exp(1j * 5))), ())
196+
assert (
197+
str(output)
198+
== """OPENQASM 2.0;
199+
include "qelib1.inc";
200+
201+
202+
// Qubits: []
203+
"""
204+
)
205+
206+
194207
def test_precision():
195208
(q0,) = _make_qubits(1)
196209
output = cirq.QasmOutput((cirq.X(q0) ** 0.1234567,), (q0,), precision=3)

Diff for: cirq-core/cirq/ops/gate_operation.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""Basic types defining qubits, gates, and operations."""
1616

1717
import re
18+
import warnings
1819
from typing import (
1920
AbstractSet,
2021
Any,
@@ -35,7 +36,7 @@
3536

3637
import numpy as np
3738

38-
from cirq import protocols, value
39+
from cirq import ops, protocols, value
3940
from cirq.ops import raw_types, gate_features, control_values as cv
4041
from cirq.type_workarounds import NotImplementedType
4142

@@ -348,6 +349,14 @@ def __rmul__(self, other: Any) -> Any:
348349
return self.gate._rmul_with_qubits(self._qubits, other)
349350

350351
def _qasm_(self, args: 'protocols.QasmArgs') -> Optional[str]:
352+
if isinstance(self.gate, ops.GlobalPhaseGate):
353+
warnings.warn(
354+
"OpenQASM 2.0 does not support global phase."
355+
"Since the global phase does not affect the measurement results, "
356+
"the conversion to QASM is disregarded."
357+
)
358+
return ""
359+
351360
return protocols.qasm(self.gate, args=args, qubits=self.qubits, default=None)
352361

353362
def _equal_up_to_global_phase_(

Diff for: cirq-core/cirq/testing/consistent_qasm.py

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def assert_qasm_is_consistent_with_unitary(val: Any):
4242
if isinstance(val, ops.Operation):
4343
qubits: Sequence[ops.Qid] = val.qubits
4444
op = val
45+
gate = val.gate
4546
elif isinstance(val, ops.Gate):
4647
qid_shape = protocols.qid_shape(val)
4748
remaining_shape = list(qid_shape)
@@ -52,9 +53,14 @@ def assert_qasm_is_consistent_with_unitary(val: Any):
5253
remaining_shape.pop(i)
5354
qubits = devices.LineQid.for_qid_shape(remaining_shape)
5455
op = val.on(*qubits)
56+
gate = val
5557
else:
5658
raise NotImplementedError(f"Don't know how to test {val!r}")
5759

60+
if isinstance(gate, ops.GlobalPhaseGate):
61+
# OpenQASM 2.0 does not support global phase gates.
62+
return
63+
5864
args = protocols.QasmArgs(qubit_id_map={q: f'q[{i}]' for i, q in enumerate(qubits)})
5965
qasm = protocols.qasm(op, args=args, default=None)
6066
if qasm is None:

Diff for: cirq-core/requirements.txt

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
duet>=0.2.8
44
matplotlib~=3.0
5+
# Temporary fix for https://github.com/sympy/sympy/issues/26273
6+
# TODO: remove once `pip install --pre sympy` works in a fresh environment
7+
mpmath<1.4
58
networkx>=2.4
69
numpy~=1.16
710
pandas

Diff for: cirq-google/cirq_google/engine/qcs_notebook.py

+48-23
Original file line numberDiff line numberDiff line change
@@ -82,32 +82,14 @@ def get_qcs_objects_for_notebook(
8282
ValueError: if processor_id is not specified and no processors are available.
8383
"""
8484

85-
# Check for Google Application Default Credentials and run
86-
# interactive login if the notebook is executed in Colab. In
87-
# case the notebook is executed in Jupyter notebook or other
88-
# IPython runtimes, no interactive login is provided, it is
89-
# assumed that the `GOOGLE_APPLICATION_CREDENTIALS` env var is
90-
# set or `gcloud auth application-default login` was executed
91-
# already. For more information on using Application Default Credentials
92-
# see https://cloud.google.com/docs/authentication/production
93-
# Attempt to connect to the Quantum Engine API, and use a simulator if unable to connect.
9485
if not virtual:
9586
# Set up auth
9687
try:
97-
from google.colab import auth
98-
except ImportError:
99-
print("Not running in a colab kernel. Will use Application Default Credentials.")
100-
else:
101-
print("Getting OAuth2 credentials.")
102-
print("Press enter after entering the verification code.")
103-
try:
104-
a = auth.authenticate_user(clear_output=False)
105-
print(a)
106-
print("Authentication complete.")
107-
except Exception as exc:
108-
print(f"Authentication failed: {exc}")
109-
print("Using virtual engine instead.")
110-
virtual = True
88+
authenticate_user()
89+
except Exception as exc:
90+
print(f"Authentication failed: {exc}")
91+
print("Using virtual engine instead.")
92+
virtual = True
11193

11294
if not virtual:
11395
# Set up production engine
@@ -152,3 +134,46 @@ def get_qcs_objects_for_notebook(
152134
processor_id=processor_id,
153135
is_simulator=is_simulator,
154136
)
137+
138+
139+
def authenticate_user(clear_output: bool = False) -> None:
140+
"""Authenticates on Google Cloud.
141+
142+
Args:
143+
clear_output: Optional bool for whether to clear output before
144+
authenticating. Defaults to false.
145+
146+
Returns:
147+
None.
148+
149+
Raises:
150+
Exception: if authentication fails.
151+
"""
152+
153+
# Check for Google Application Default Credentials and run
154+
# interactive login if the notebook is executed in Colab. In
155+
# case the notebook is executed in Jupyter notebook or other
156+
# IPython runtimes, no interactive login is provided, it is
157+
# assumed that the `GOOGLE_APPLICATION_CREDENTIALS` env var is
158+
# set or `gcloud auth application-default login` was executed
159+
# already. For more information on using Application Default Credentials
160+
# see https://cloud.google.com/docs/authentication/production
161+
# Attempt to connect to the Quantum Engine API, and use a simulator if unable to connect.
162+
try:
163+
from google.colab import auth
164+
except ImportError:
165+
print("Not running in a colab kernel. Will use Application Default Credentials.")
166+
return
167+
168+
try:
169+
print("Getting OAuth2 credentials.")
170+
print("Press enter after entering the verification code.")
171+
a = auth.authenticate_user(clear_output=clear_output)
172+
print(a)
173+
print("Authentication complete.")
174+
except Exception as exc:
175+
print(
176+
"Authentication failed, you may not have permission to access a"
177+
+ " hardware Engine. Use a virtual Engine instead."
178+
)
179+
raise exc

Diff for: cirq-google/cirq_google/engine/qcs_notebook_test.py

+41-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
import pytest
1818

1919
import cirq_google as cg
20-
from cirq_google.engine.qcs_notebook import get_qcs_objects_for_notebook, QCSObjectsForNotebook
20+
from cirq_google.engine.qcs_notebook import (
21+
get_qcs_objects_for_notebook,
22+
QCSObjectsForNotebook,
23+
authenticate_user,
24+
)
2125

2226

2327
def _assert_correct_types(result: QCSObjectsForNotebook):
@@ -132,3 +136,39 @@ def test_get_qcs_objects_for_notebook_auth_fails(engine_mock):
132136
assert not result.signed_in
133137
assert result.is_simulator
134138
assert result.project_id == 'fake_project'
139+
140+
141+
class TestAuthenticateUser:
142+
"""Tests for the public API `get_hardware_engine_and_authenticate_user` which
143+
authenticates the user and returns a production engine instance ."""
144+
145+
@mock.patch.dict('sys.modules', {'google.colab': mock.Mock()})
146+
def test_authentication_succeeds_no_exceptions_thrown(self):
147+
auth_mock = sys.modules['google.colab']
148+
149+
authenticate_user()
150+
151+
assert auth_mock.auth.authenticate_user.called
152+
153+
@mock.patch.dict('sys.modules', {'google.colab': mock.Mock()})
154+
def test_authentication_failure(self):
155+
project_id = "invalid-project"
156+
# Mock authentication failure
157+
auth_mock = sys.modules['google.colab']
158+
159+
auth_mock.auth.authenticate_user = mock.Mock(side_effect=Exception('mock auth failure'))
160+
161+
with pytest.raises(Exception, match="mock auth failure"):
162+
authenticate_user(project_id)
163+
164+
@mock.patch.dict('sys.modules', {'google.colab': mock.Mock()})
165+
@pytest.mark.parametrize('clear_output', ([True, False]))
166+
def test_clear_output_is_passed(self, clear_output):
167+
auth_mock = sys.modules['google.colab']
168+
169+
with mock.patch.object(
170+
auth_mock.auth, 'authenticate_user', return_value=None
171+
) as mock_authenticate_user:
172+
authenticate_user(clear_output)
173+
174+
mock_authenticate_user.assert_called_with(clear_output=clear_output)

Diff for: dev_tools/docker_test.py

-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ def test_docker_stable():
2222
assert result.returncode == 0
2323

2424

25-
@pytest.mark.skip(reason="fails due to boken dependendencies #6475")
2625
def test_docker_pre():
2726
if platform.system() != 'Linux':
2827
pytest.skip("Unsupported os")

Diff for: docs/tutorials/google/start.ipynb

+15-12
Original file line numberDiff line numberDiff line change
@@ -132,22 +132,24 @@
132132
"cell_type": "code",
133133
"execution_count": null,
134134
"metadata": {
135-
"id": "YoqI9GrOPExP",
136-
"cellView": "form"
135+
"id": "YoqI9GrOPExP"
137136
},
138137
"outputs": [],
139138
"source": [
140139
"# The Google Cloud Project id to use.\n",
141140
"project_id = \"\" #@param {type:\"string\"}\n",
142141
"\n",
143-
"from cirq_google.engine.qcs_notebook import get_qcs_objects_for_notebook\n",
144-
"# For virtual engine instances, set 'virtual=True' below.\n",
145-
"qcs_objects = get_qcs_objects_for_notebook(project_id)\n",
142+
"from cirq_google.engine import get_engine\n",
143+
"from cirq_google.engine.qcs_notebook import authenticate_user\n",
146144
"\n",
147-
"engine = qcs_objects.engine\n",
148-
"if not qcs_objects.signed_in:\n",
149-
" print(\"ERROR: Please setup project_id in this cell or set the `GOOGLE_CLOUD_PROJECT` env var to your project id.\")\n",
150-
" print(\"Using noisy simulator instead.\")\n"
145+
"authenticate_user()\n",
146+
"try:\n",
147+
" engine = get_engine(project_id)\n",
148+
"except Exception:\n",
149+
" from cirq_google.engine.qcs_notebook import get_qcs_objects_for_notebook\n",
150+
" print(\"Unable to connect to a hardware engine. Using a virtual instance instead.\")\n",
151+
" qcs_objects = get_qcs_objects_for_notebook(project_id, virtual=True)\n",
152+
" engine = qcs_objects.engine"
151153
]
152154
},
153155
{
@@ -175,11 +177,11 @@
175177
},
176178
{
177179
"cell_type": "code",
178-
"execution_count": 9,
180+
"execution_count": 24,
179181
"metadata": {
180182
"cellView": "both",
181183
"id": "EQoTYZIEPa9S",
182-
"outputId": "43c72568-3bc8-4b44-871b-b9db19c9e672",
184+
"outputId": "beb04676-8404-4831-8d40-3291ee2d6127",
183185
"colab": {
184186
"base_uri": "https://localhost:8080/"
185187
}
@@ -275,7 +277,8 @@
275277
{
276278
"cell_type": "code",
277279
"source": [
278-
"processors = [p.processor_id for p in engine.list_processors() if p.health() == 'OK']"
280+
"processors = [p.processor_id for p in engine.list_processors() if p.health() == 'OK']\n",
281+
"print(f\"Available processors: {processors}\")"
279282
],
280283
"metadata": {
281284
"id": "rvMeXrC1wnQi"

0 commit comments

Comments
 (0)