Skip to content

Commit

Permalink
Merge branch 'main' into rigetti-use-pyquil-v4
Browse files Browse the repository at this point in the history
  • Loading branch information
jselig-rigetti authored Mar 12, 2024
2 parents 0b7c216 + bc76660 commit 25ef38d
Show file tree
Hide file tree
Showing 16 changed files with 442 additions and 101 deletions.
7 changes: 6 additions & 1 deletion cirq-core/cirq/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@

from cirq.testing.equivalent_repr_eval import assert_equivalent_repr

from cirq.testing.gate_features import SingleQubitGate, TwoQubitGate, ThreeQubitGate
from cirq.testing.gate_features import (
SingleQubitGate,
TwoQubitGate,
ThreeQubitGate,
DoesNotSupportSerializationGate,
)

from cirq.testing.json import assert_json_roundtrip_works

Expand Down
10 changes: 10 additions & 0 deletions cirq-core/cirq/testing/gate_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,13 @@ class ThreeQubitGate(raw_types.Gate):

def _num_qubits_(self) -> int:
return 3


class DoesNotSupportSerializationGate(raw_types.Gate):
"""A gate that can't be serialized."""

def __init__(self, n_qubits: int = 1):
self.n_qubits = n_qubits

def _num_qubits_(self) -> int:
return self.n_qubits
23 changes: 23 additions & 0 deletions cirq-google/cirq_google/api/v2/program.proto
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ message Operation {
WaitGate waitgate = 16;
InternalGate internalgate = 17;
CouplerPulseGate couplerpulsegate = 18;
IdentityGate identitygate = 19;
HPowGate hpowgate = 20;
SingleQubitCliffordGate singlequbitcliffordgate = 21;
}

// Map from the argument name to the Argument needed to fully specify
Expand Down Expand Up @@ -434,4 +437,24 @@ message CouplerPulseGate{
optional FloatArg coupling_mhz = 4;
optional FloatArg q0_detune_mhz = 5;
optional FloatArg q1_detune_mhz = 6;
}

message CliffordTableau {
optional int32 num_qubits = 1; // Number of qubits the CliffordTableau acts on.
optional int32 initial_state = 2; // The initial state.
repeated bool rs = 3; // A flattened version of the `rs` array.
repeated bool xs = 4; // A flattened version of the `xs` array.
repeated bool zs = 5; // A flattened version of the `zs` array.
}

message SingleQubitCliffordGate {
CliffordTableau tableau = 1;
}

message IdentityGate {
repeated uint32 qid_shape = 1;
}

message HPowGate {
FloatArg exponent = 1;
}
104 changes: 56 additions & 48 deletions cirq-google/cirq_google/api/v2/program_pb2.py

Large diffs are not rendered by default.

108 changes: 105 additions & 3 deletions cirq-google/cirq_google/api/v2/program_pb2.pyi

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion cirq-google/cirq_google/devices/grid_device_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,9 @@ def test_grid_device_validate_operations_negative():
device.validate_operation(cirq.CZ(q00, q10))

with pytest.raises(ValueError, match='gate which is not supported'):
device.validate_operation(cirq.H(device_info.grid_qubits[0]))
device.validate_operation(
cirq.testing.DoesNotSupportSerializationGate()(device_info.grid_qubits[0])
)


@pytest.mark.parametrize(
Expand Down
4 changes: 3 additions & 1 deletion cirq-google/cirq_google/engine/engine_processor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,9 @@ def test_get_device():
with pytest.raises(ValueError):
device.validate_operation(cirq.X(cirq.GridQubit(1, 2)))
with pytest.raises(ValueError):
device.validate_operation(cirq.H(cirq.GridQubit(0, 0)))
device.validate_operation(
cirq.testing.DoesNotSupportSerializationGate()(cirq.GridQubit(0, 0))
)
with pytest.raises(ValueError):
device.validate_operation(cirq.CZ(cirq.GridQubit(1, 1), cirq.GridQubit(2, 2)))

Expand Down
4 changes: 3 additions & 1 deletion cirq-google/cirq_google/engine/engine_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,8 @@ def test_get_engine_device(get_processor):
with pytest.raises(ValueError):
device.validate_operation(cirq.X(cirq.GridQubit(1, 2)))
with pytest.raises(ValueError):
device.validate_operation(cirq.H(cirq.GridQubit(0, 0)))
device.validate_operation(
cirq.testing.DoesNotSupportSerializationGate()(cirq.GridQubit(0, 0))
)
with pytest.raises(ValueError):
device.validate_operation(cirq.CZ(cirq.GridQubit(1, 1), cirq.GridQubit(2, 2)))
71 changes: 48 additions & 23 deletions cirq-google/cirq_google/engine/qcs_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,32 +82,14 @@ def get_qcs_objects_for_notebook(
ValueError: if processor_id is not specified and no processors are available.
"""

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

if not virtual:
# Set up production engine
Expand Down Expand Up @@ -152,3 +134,46 @@ def get_qcs_objects_for_notebook(
processor_id=processor_id,
is_simulator=is_simulator,
)


def authenticate_user(clear_output: bool = False) -> None:
"""Authenticates on Google Cloud.
Args:
clear_output: Optional bool for whether to clear output before
authenticating. Defaults to false.
Returns:
None.
Raises:
Exception: if authentication fails.
"""

# Check for Google Application Default Credentials and run
# interactive login if the notebook is executed in Colab. In
# case the notebook is executed in Jupyter notebook or other
# IPython runtimes, no interactive login is provided, it is
# assumed that the `GOOGLE_APPLICATION_CREDENTIALS` env var is
# set or `gcloud auth application-default login` was executed
# already. For more information on using Application Default Credentials
# see https://cloud.google.com/docs/authentication/production
# Attempt to connect to the Quantum Engine API, and use a simulator if unable to connect.
try:
from google.colab import auth
except ImportError:
print("Not running in a colab kernel. Will use Application Default Credentials.")
return

try:
print("Getting OAuth2 credentials.")
print("Press enter after entering the verification code.")
a = auth.authenticate_user(clear_output=clear_output)
print(a)
print("Authentication complete.")
except Exception as exc:
print(
"Authentication failed, you may not have permission to access a"
+ " hardware Engine. Use a virtual Engine instead."
)
raise exc
42 changes: 41 additions & 1 deletion cirq-google/cirq_google/engine/qcs_notebook_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
import pytest

import cirq_google as cg
from cirq_google.engine.qcs_notebook import get_qcs_objects_for_notebook, QCSObjectsForNotebook
from cirq_google.engine.qcs_notebook import (
get_qcs_objects_for_notebook,
QCSObjectsForNotebook,
authenticate_user,
)


def _assert_correct_types(result: QCSObjectsForNotebook):
Expand Down Expand Up @@ -132,3 +136,39 @@ def test_get_qcs_objects_for_notebook_auth_fails(engine_mock):
assert not result.signed_in
assert result.is_simulator
assert result.project_id == 'fake_project'


class TestAuthenticateUser:
"""Tests for the public API `get_hardware_engine_and_authenticate_user` which
authenticates the user and returns a production engine instance ."""

@mock.patch.dict('sys.modules', {'google.colab': mock.Mock()})
def test_authentication_succeeds_no_exceptions_thrown(self):
auth_mock = sys.modules['google.colab']

authenticate_user()

assert auth_mock.auth.authenticate_user.called

@mock.patch.dict('sys.modules', {'google.colab': mock.Mock()})
def test_authentication_failure(self):
project_id = "invalid-project"
# Mock authentication failure
auth_mock = sys.modules['google.colab']

auth_mock.auth.authenticate_user = mock.Mock(side_effect=Exception('mock auth failure'))

with pytest.raises(Exception, match="mock auth failure"):
authenticate_user(project_id)

@mock.patch.dict('sys.modules', {'google.colab': mock.Mock()})
@pytest.mark.parametrize('clear_output', ([True, False]))
def test_clear_output_is_passed(self, clear_output):
auth_mock = sys.modules['google.colab']

with mock.patch.object(
auth_mock.auth, 'authenticate_user', return_value=None
) as mock_authenticate_user:
authenticate_user(clear_output)

mock_authenticate_user.assert_called_with(clear_output=clear_output)
8 changes: 6 additions & 2 deletions cirq-google/cirq_google/engine/virtual_engine_factory_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ def _test_processor(processor: cg.engine.abstract_processor.AbstractProcessor):
circuit = cirq.Circuit(cirq.X(bad_qubit), cirq.measure(bad_qubit))
with pytest.raises(ValueError, match='Qubit not on device'):
_ = processor.run(circuit, repetitions=100)
circuit = cirq.Circuit(cirq.H(good_qubit), cirq.measure(good_qubit))
circuit = cirq.Circuit(
cirq.testing.DoesNotSupportSerializationGate()(good_qubit), cirq.measure(good_qubit)
)
with pytest.raises(ValueError, match='Cannot serialize op'):
_ = processor.run(circuit, repetitions=100)

Expand Down Expand Up @@ -195,7 +197,9 @@ def test_create_default_noisy_quantum_virtual_machine():
with pytest.raises(ValueError, match='Qubit not on device'):
_ = processor.run(circuit, repetitions=100)
good_qubit = cirq.GridQubit(5, 4)
circuit = cirq.Circuit(cirq.H(good_qubit), cirq.measure(good_qubit))
circuit = cirq.Circuit(
cirq.testing.DoesNotSupportSerializationGate()(good_qubit), cirq.measure(good_qubit)
)
with pytest.raises(ValueError, match='.* contains a gate which is not supported.'):
_ = processor.run(circuit, repetitions=100)
device_specification = processor.get_device_specification()
Expand Down
Loading

0 comments on commit 25ef38d

Please sign in to comment.