Skip to content

Commit

Permalink
Merge branch 'master' of github.com:quantumlib/Cirq into stream-clien…
Browse files Browse the repository at this point in the history
…t/stream-manager-asyncio-heavy
  • Loading branch information
verult committed Aug 3, 2023
2 parents 9a62f66 + 701538c commit dec6705
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 33 deletions.
2 changes: 1 addition & 1 deletion cirq-core/cirq/testing/consistent_qasm_test.py
Expand Up @@ -84,7 +84,7 @@ def test_assert_qasm_is_consistent_with_unitary():
)

# Checks that code is valid.
with pytest.raises(AssertionError, match='Check your OPENQASM'):
with pytest.raises(AssertionError, match='QASM not consistent'):
cirq.testing.assert_qasm_is_consistent_with_unitary(
Fixed(np.array([[1, 0], [0, -1]]), 'JUNK$&*@($#::=[];')
)
Expand Down
4 changes: 3 additions & 1 deletion cirq-ft/cirq_ft/infra/gate_with_registers.py
Expand Up @@ -122,7 +122,9 @@ def merge_qubits(
) -> List[cirq.Qid]:
ret: List[cirq.Qid] = []
for reg in self:
assert reg.name in qubit_regs, "All qubit registers must pe present"
assert (
reg.name in qubit_regs
), f"All qubit registers must be present. {reg.name} not in qubit_regs"
qubits = qubit_regs[reg.name]
qubits = np.array([qubits] if isinstance(qubits, cirq.Qid) else qubits)
assert (
Expand Down
22 changes: 14 additions & 8 deletions cirq-google/cirq_google/engine/asyncio_executor.py
Expand Up @@ -12,14 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Awaitable, Callable, TypeVar
from typing import Awaitable, Callable, Optional, TypeVar
import asyncio
import threading

import asyncio
from typing_extensions import ParamSpec

import duet


_R = TypeVar('_R')
R = TypeVar('R')
P = ParamSpec("P")


class AsyncioExecutor:
Expand All @@ -42,23 +45,26 @@ async def _main(loop_future: duet.AwaitableFuture) -> None:
while True:
await asyncio.sleep(1)

def submit(self, func: Callable[..., Awaitable[_R]], *args, **kw) -> duet.AwaitableFuture[_R]:
def submit(
self, func: Callable[P, Awaitable[R]], *args: P.args, **kwargs: P.kwargs
) -> duet.AwaitableFuture[R]:
"""Dispatch the given function to be run in an asyncio coroutine.
Args:
func: asyncio function which will be run in a separate thread.
Will be called with *args and **kw and should return an asyncio
awaitable.
*args: Positional args to pass to func.
**kw: Keyword args to pass to func.
**kwargs: Keyword args to pass to func.
"""
future = asyncio.run_coroutine_threadsafe(func(*args, **kw), self.loop)
future = asyncio.run_coroutine_threadsafe(func(*args, **kwargs), self.loop)
return duet.AwaitableFuture.wrap(future)

_instance = None
_instance: Optional['AsyncioExecutor'] = None

@classmethod
def instance(cls):
def instance(cls) -> 'AsyncioExecutor':
"""Returns a singleton AsyncioExecutor shared globally."""
if cls._instance is None:
cls._instance = cls()
return cls._instance
28 changes: 15 additions & 13 deletions cirq-google/cirq_google/serialization/circuit_serializer.py
Expand Up @@ -14,7 +14,7 @@

"""Support for serializing and deserializing cirq_google.api.v2 protos."""

from typing import cast, Any, Dict, List, Optional
from typing import Any, Dict, List, Optional
import sympy

import cirq
Expand Down Expand Up @@ -546,20 +546,22 @@ def _deserialize_gate_op(
arg_function_language=arg_function_language,
required_arg_name=None,
)
invert_mask = cast(
List[bool],
arg_func_langs.arg_from_proto(
operation_proto.measurementgate.invert_mask,
arg_function_language=arg_function_language,
required_arg_name=None,
),
parsed_invert_mask = arg_func_langs.arg_from_proto(
operation_proto.measurementgate.invert_mask,
arg_function_language=arg_function_language,
required_arg_name=None,
)
if isinstance(invert_mask, list) and isinstance(key, str):
op = cirq.MeasurementGate(
num_qubits=len(qubits), key=key, invert_mask=tuple(invert_mask)
)(*qubits)
if (isinstance(parsed_invert_mask, list) or parsed_invert_mask is None) and isinstance(
key, str
):
invert_mask: tuple[bool, ...] = ()
if parsed_invert_mask is not None:
invert_mask = tuple(bool(x) for x in parsed_invert_mask)
op = cirq.MeasurementGate(num_qubits=len(qubits), key=key, invert_mask=invert_mask)(
*qubits
)
else:
raise ValueError(f'Incorrect types for measurement gate {invert_mask} {key}')
raise ValueError(f'Incorrect types for measurement gate {parsed_invert_mask} {key}')

elif which_gate_type == 'waitgate':
total_nanos = arg_func_langs.float_arg_from_proto(
Expand Down
Expand Up @@ -660,3 +660,11 @@ def test_no_constants_table():

with pytest.raises(ValueError, match='Proto has references to constants table'):
serializer._deserialize_gate_op(op)


def test_measurement_gate_deserialize() -> None:
q = cirq.NamedQubit('q')
circuit = cirq.Circuit(cirq.X(q) ** 0.5, cirq.measure(q))
msg = cg.CIRCUIT_SERIALIZER.serialize(circuit)

assert cg.CIRCUIT_SERIALIZER.deserialize(msg) == circuit
7 changes: 5 additions & 2 deletions cirq-ionq/cirq_ionq/service.py
Expand Up @@ -62,9 +62,12 @@ def __init__(
This is actually an EnvironmentError which is equal to an OSError.
"""
self.remote_host = (
remote_host or os.getenv('IONQ_REMOTE_HOST') or f'https://api.ionq.co/{api_version}'
remote_host
or os.getenv('CIRQ_IONQ_REMOTE_HOST')
or os.getenv('IONQ_REMOTE_HOST')
or f'https://api.ionq.co/{api_version}'
)
self.api_key = api_key or os.getenv('IONQ_API_KEY')
self.api_key = api_key or os.getenv('CIRQ_IONQ_API_KEY') or os.getenv('IONQ_API_KEY')
if not self.api_key:
raise EnvironmentError(
'Parameter api_key was not specified and the environment variable '
Expand Down
66 changes: 61 additions & 5 deletions cirq-ionq/cirq_ionq/service_test.py
Expand Up @@ -158,25 +158,81 @@ def test_service_list_calibrations():
mock_client.list_calibrations.assert_called_with(start=start, end=end, limit=10, batch_size=2)


@mock.patch.dict(os.environ, {'IONQ_API_KEY': 'tomyheart'})
def test_service_api_key_via_env():
os.environ['IONQ_API_KEY'] = 'tomyheart'
service = ionq.Service(remote_host='http://example.com')
assert service.api_key == 'tomyheart'
del os.environ['IONQ_API_KEY']


@mock.patch.dict(os.environ, {'IONQ_REMOTE_HOST': 'http://example.com'})
def test_service_remote_host_via_env():
os.environ['IONQ_REMOTE_HOST'] = 'http://example.com'
service = ionq.Service(api_key='tomyheart')
assert service.remote_host == 'http://example.com'
del os.environ['IONQ_REMOTE_HOST']


@mock.patch.dict(os.environ, {}, clear=True)
def test_service_no_param_or_env_variable():
with pytest.raises(EnvironmentError):
_ = ionq.Service(remote_host='http://example.com')


def test_service_no_url_default():
@mock.patch.dict(os.environ, {'IONQ_API_KEY': 'not_this_key'})
def test_service_api_key_passed_directly():
service = ionq.Service(remote_host='http://example.com', api_key='tomyheart')
assert service.api_key == 'tomyheart'


@mock.patch.dict(os.environ, {'CIRQ_IONQ_API_KEY': 'tomyheart'})
def test_service_api_key_from_env_var_cirq_ionq():
service = ionq.Service(remote_host='http://example.com')
assert service.api_key == 'tomyheart'


@mock.patch.dict(os.environ, {'IONQ_API_KEY': 'tomyheart'})
def test_service_api_key_from_env_var_ionq():
service = ionq.Service(remote_host='http://example.com')
assert service.api_key == 'tomyheart'


@mock.patch.dict(os.environ, {}, clear=True)
def test_service_api_key_not_found_raises_error():
with pytest.raises(EnvironmentError):
_ = ionq.Service(remote_host='http://example.com')


@mock.patch.dict(os.environ, {'CIRQ_IONQ_API_KEY': 'tomyheart', 'IONQ_API_KEY': 'not_this_key'})
def test_service_api_key_from_env_var_cirq_ionq_precedence():
service = ionq.Service(remote_host='http://example.com')
assert service.api_key == 'tomyheart'


@mock.patch.dict(os.environ, {'CIRQ_IONQ_REMOTE_HOST': 'not_this_host'})
def test_service_remote_host_passed_directly():
service = ionq.Service(remote_host='http://example.com', api_key='tomyheart')
assert service.remote_host == 'http://example.com'


@mock.patch.dict(os.environ, {'CIRQ_IONQ_REMOTE_HOST': 'http://example.com'})
def test_service_remote_host_from_env_var_cirq_ionq():
service = ionq.Service(api_key='tomyheart')
assert service.remote_host == 'http://example.com'


@mock.patch.dict(os.environ, {'IONQ_REMOTE_HOST': 'http://example.com'})
def test_service_remote_host_from_env_var_ionq():
service = ionq.Service(api_key='tomyheart')
assert service.remote_host == 'http://example.com'


@mock.patch.dict(os.environ, {}, clear=True)
def test_service_remote_host_default():
service = ionq.Service(api_key='tomyheart', api_version='v0.1')
assert service.remote_host == 'https://api.ionq.co/v0.1'


@mock.patch.dict(
os.environ, {'CIRQ_IONQ_REMOTE_HOST': 'http://example.com', 'IONQ_REMOTE_HOST': 'not_this_host'}
)
def test_service_remote_host_from_env_var_cirq_ionq_precedence():
service = ionq.Service(api_key='tomyheart')
assert service.remote_host == 'http://example.com'
2 changes: 1 addition & 1 deletion cirq-rigetti/requirements.txt
@@ -1 +1 @@
pyquil~=3.2.0
pyquil>=3.2.0,<4.0.0
2 changes: 1 addition & 1 deletion dev_tools/requirements/deps/mypy.txt
Expand Up @@ -4,6 +4,6 @@ mypy==1.2.0
# packages with stub types for various libraries
types-backports==0.1.3
types-cachetools
types-protobuf==3.19.22
types-protobuf~=3.20
types-requests==2.28.1
types-setuptools==62.6.1
2 changes: 1 addition & 1 deletion dev_tools/requirements/deps/protos.txt
Expand Up @@ -3,4 +3,4 @@
# This bundles protoc 3.23.1, which we use for generating proto code.
grpcio-tools~=1.56.0

mypy-protobuf
mypy-protobuf==3.4

0 comments on commit dec6705

Please sign in to comment.