Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
77eec1a
Add `ProcessorConfig` and `ProcessorConfigSnapshot`
dyates Jul 7, 2025
69f1397
Update __init__; Add another unit test.
dyates Jul 7, 2025
a8e8262
Merge branch 'main' into add_get_config_snapshot
dyates Jul 7, 2025
df98f15
Regenerates QuantumEngineService gRPC client libraries with GAPIC
hoisinberg Jul 16, 2025
5fb5fbc
Merge branch 'main' into add_get_config_snapshot
dyates Jul 21, 2025
3b29858
Merge remote-tracking branch 'upstream/u/hoisinberg/get-quantum-proce…
dyates Jul 21, 2025
71dad68
Merge branch 'main' into add_get_config_snapshot
dyates Jul 23, 2025
7cbcdc1
Merge branch 'main' into add_get_config_snapshot
dyates Jul 29, 2025
6866f26
Add `get_quantum_processor_config_by_snapshot_id`
dyates Jul 30, 2025
20ca033
Add unit test for missing config.
dyates Jul 30, 2025
b3413a4
Add `get_quantum_processor_config_by_run_name`.
dyates Jul 30, 2025
eed577d
Implement `get_config` for `ProcessorConfigSnapshot`.
dyates Jul 31, 2025
cc447ff
Add `get_config*` functions to EngineProcessor.
dyates Aug 4, 2025
c30bde8
Sync changes
dyates Aug 5, 2025
b1ef097
Merge branch 'main' into add_get_config_snapshot
dyates Aug 5, 2025
2eb9ee9
Add `AbstractProcessorConfig` interface.
dyates Aug 8, 2025
aee07e6
Add `get_config*` methods to the `Engine` class.
dyates Aug 8, 2025
bc7db00
Merge branch 'main' into add_get_config_snapshot
dyates Aug 8, 2025
9e2fdcd
Add missing methods from other abstract engines and processors.
dyates Aug 8, 2025
cc4b43e
Add test for __repr__; Remove config logic from LocalAbstractEnginer.
dyates Aug 11, 2025
6835a61
Update imports.
dyates Aug 11, 2025
e96871c
Fix more formatting errors.
dyates Aug 11, 2025
e2429c3
Update test and linting errors.
dyates Aug 11, 2025
093cd1e
More formatting fixes.
dyates Aug 11, 2025
11d97f5
More fixes.
dyates Aug 11, 2025
2365a57
Fix test name
dyates Aug 11, 2025
67cabf4
More syntax errors.
dyates Aug 11, 2025
afe7f0e
More formatting fixes.
dyates Aug 11, 2025
947ad46
Fix remaining format issues
dyates Aug 11, 2025
4783519
Add missing documentation.
dyates Aug 11, 2025
3d1e101
Merge branch 'main' into add_get_config_functions
dyates Aug 15, 2025
1505ba8
Rename parameters and functioncs for consistency.
dyates Aug 15, 2025
f7bba28
Fix function params in AbstractLocalEngine
dyates Aug 15, 2025
f15e751
More `check/` fixes.
dyates Aug 15, 2025
449fdd4
More check fixes.
dyates Aug 15, 2025
d259f1a
Merge branch 'main' into add_get_config_functions
dyates Aug 22, 2025
6eba4b4
Address new comments.
dyates Aug 22, 2025
cd81646
Remove unused imports.
dyates Aug 22, 2025
4a03de1
Update import format.
dyates Aug 22, 2025
000ce5d
Update doc comments to mention default configs.
dyates Aug 25, 2025
00e2f36
Merge branch 'main' into add_get_config_functions
dyates Aug 25, 2025
4584bff
Remove N/A changes.
dyates Aug 25, 2025
a89213e
Remove changes to simulated_* engine files.
dyates Aug 25, 2025
f9ef67a
Change `config_alias` to `config_name`.
dyates Aug 29, 2025
7059f1a
Merge branch 'main' into add_get_config_functions
dyates Aug 29, 2025
32ad541
Remove config functions from local processor unit test.
dyates Aug 29, 2025
2ef6805
Format fixes.
dyates Aug 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cirq-google/cirq_google/engine/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,5 @@
from cirq_google.engine.engine_result import EngineResult as EngineResult

from cirq_google.engine.processor_sampler import ProcessorSampler as ProcessorSampler

from cirq_google.engine.processor_config import ProcessorConfig as ProcessorConfig
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ def list_programs(
def get_program(self, program_id: str) -> AbstractProgram:
return self._programs[program_id]

def get_config_from_run(self, *args, **kwargs):
pass

def get_config_from_snapshot(self, *args, **kwargs):
pass


class NothingEngine(AbstractLocalEngine):
"""Engine for Testing."""
Expand Down
57 changes: 57 additions & 0 deletions cirq-google/cirq_google/engine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
engine_job,
engine_processor,
engine_program,
processor_config,
util,
)
from cirq_google.serialization import CIRCUIT_SERIALIZER, Serializer
Expand Down Expand Up @@ -635,6 +636,62 @@ def get_sampler(
max_concurrent_jobs=max_concurrent_jobs,
)

async def get_processor_config_from_snapshot_async(
self, processor_id: str, snapshot_id: str, config_name: str = 'default'
) -> processor_config.ProcessorConfig | None:
"""Returns a ProcessorConfig from this project and the given processor id.

Args:
processor_id: The processor unique identifier.
snapshot_id: The unique identifier for the snapshot.
config_name: The identifier for the config.

Returns:
The ProcessorConfig from this project and processor.
"""
client = self.context.client
quantum_config = await client.get_quantum_processor_config_from_snapshot_async(
project_id=self.project_id,
processor_id=processor_id,
snapshot_id=snapshot_id,
config_name=config_name,
)
if quantum_config:
return processor_config.ProcessorConfig(quantum_processor_config=quantum_config)
return None

get_processor_config_from_snapshot = duet.sync(get_processor_config_from_snapshot_async)

async def get_processor_config_from_run_async(
self, processor_id: str, run_name: str = 'current', config_name: str = 'default'
) -> processor_config.ProcessorConfig | None:
"""Returns a ProcessorConfig from this project and the given processor id.

If no `run_name` and `config_name` are specified, the inernally configured default config
is returned.

Args:
processor_id: The processor unique identifier.
run_name: The unique identifier for the automation run.
config_name: The identifier for the config.

Returns:
The ProcessorConfig from this project and processor.
"""
quantum_config = await self.context.client.get_quantum_processor_config_from_run_async(
project_id=self.project_id,
processor_id=processor_id,
run_name=run_name,
config_name=config_name,
)
if quantum_config:
return processor_config.ProcessorConfig(
quantum_processor_config=quantum_config, run_name=run_name
)
return None

get_processor_config_from_run = duet.sync(get_processor_config_from_run_async)


def get_engine(project_id: str | None = None) -> Engine:
"""Get an Engine instance assuming some sensible defaults.
Expand Down
92 changes: 92 additions & 0 deletions cirq-google/cirq_google/engine/engine_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,76 @@ async def list_time_slots_async(

list_time_slots = duet.sync(list_time_slots_async)

async def _get_quantum_processor_config(
self, name: str
) -> quantum.QuantumProcessorConfig | None:
"""Runs get_quantum_processor_config with the given resource name."""
try:
request = quantum.GetQuantumProcessorConfigRequest(name=name)
return await self._send_request_async(
self.grpc_client.get_quantum_processor_config, request
)
except EngineException as err:
if isinstance(err.__cause__, NotFound):
return None
raise

async def get_quantum_processor_config_from_snapshot_async(
self, project_id: str, processor_id: str, snapshot_id: str, config_name: str
) -> quantum.QuantumProcessorConfig | None:
"""Returns the QuantumProcessorConfig for the given snapshot id.

Args:
project_id: A project_id of the parent Google Cloud Project.
processor_id: The processor unique identifier.
snapshot_id: The id of the snapshot that contains the quantum processor config.
config_name: The id of the quantum processor config.

Returns:
The quantum procesor config or None if it does not exist.

Raises:
EngineException: If the request to get the config fails.
"""
name = _quantum_processor_name_with_snapshot_id(
project_id=project_id,
processor_id=processor_id,
snapshot_id=snapshot_id,
config_name=config_name,
)
return await self._get_quantum_processor_config(name)

get_quantum_processor_config_from_snapshot = duet.sync(
get_quantum_processor_config_from_snapshot_async
)

async def get_quantum_processor_config_from_run_async(
self, project_id: str, processor_id: str, run_name: str, config_name: str
) -> quantum.QuantumProcessorConfig | None:
"""Returns the QuantumProcessorConfig for the given run_name.

Args:
project_id: A project_id of the parent Google Cloud Project.
processor_id: The processor unique identifier.
config_name: The id of the quantum processor config.
run_name: The run_name that contains the quantum processor config.

Returns:
The quantum procesor config or None if it does not exist.

Raises:
EngineException: If the request to get the config fails.
"""
name = _quantum_processor_name_with_run_name(
project_id=project_id,
processor_id=processor_id,
run_name=run_name,
config_name=config_name,
)
return await self._get_quantum_processor_config(name)

get_quantum_processor_config_from_run = duet.sync(get_quantum_processor_config_from_run_async)


def _project_name(project_id: str) -> str:
return f'projects/{project_id}'
Expand Down Expand Up @@ -1230,6 +1300,28 @@ def _ids_from_calibration_name(calibration_name: str) -> tuple[str, str, int]:
return parts[1], parts[3], int(parts[5])


def _quantum_processor_name_with_snapshot_id(
project_id: str, processor_id: str, snapshot_id: str, config_name: str
) -> str:
return (
f'projects/{project_id}/'
f'processors/{processor_id}/'
f'configSnapshots/{snapshot_id}/'
f'configs/{config_name}'
)


def _quantum_processor_name_with_run_name(
project_id: str, processor_id: str, run_name: str, config_name: str
) -> str:
return (
f'projects/{project_id}/'
f'processors/{processor_id}/'
f'configAutomationRuns/{run_name}/'
f'configs/{config_name}'
)


def _date_or_time_to_filter_expr(param_name: str, param: datetime.datetime | datetime.date):
"""Formats datetime or date to filter expressions.

Expand Down
141 changes: 141 additions & 0 deletions cirq-google/cirq_google/engine/engine_client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1743,3 +1743,144 @@ def test_list_time_slots(client_constructor, default_engine_client):
grpc_client.list_quantum_time_slots.return_value = Pager(results)

assert default_engine_client.list_time_slots('proj', 'processor0') == results


@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_get_quantum_processor_config_from_snapshot(client_constructor, default_engine_client):

project_id = "test_project_id"
processor_id = "test_processor_id"
snapshot_id = "test_snapshot_id"
config_name = "test_config_name"
resource_name = (
f'projects/{project_id}/'
f'processors/{processor_id}/'
f'configSnapshots/{snapshot_id}/'
f'configs/{config_name}'
)

grpc_client = _setup_client_mock(client_constructor)
expected_result = quantum.QuantumProcessorConfig(name=resource_name)
grpc_client.get_quantum_processor_config.return_value = expected_result

actual_result = default_engine_client.get_quantum_processor_config_from_snapshot(
project_id=project_id,
processor_id=processor_id,
config_name=config_name,
snapshot_id=snapshot_id,
)
grpc_client.get_quantum_processor_config.assert_called_with(
quantum.GetQuantumProcessorConfigRequest(name=resource_name)
)
assert actual_result == expected_result


@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_get_quantum_processor_config_from_snapshot_not_found(
client_constructor, default_engine_client
):
project_id = "test_project_id"
processor_id = "test_processor_id"
snapshot_id = "test_snapshot_id"
config_name = "test_config_name"
resource_name = (
f'projects/{project_id}/'
f'processors/{processor_id}/'
f'configSnapshots/{snapshot_id}/'
f'configs/{config_name}'
)

grpc_client = _setup_client_mock(client_constructor)
grpc_client.get_quantum_processor_config.side_effect = exceptions.NotFound('not found')

actual_result = default_engine_client.get_quantum_processor_config_from_snapshot(
project_id=project_id,
processor_id=processor_id,
config_name=config_name,
snapshot_id=snapshot_id,
)
grpc_client.get_quantum_processor_config.assert_called_with(
quantum.GetQuantumProcessorConfigRequest(name=resource_name)
)
assert actual_result is None


@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_get_quantum_processor_config_from_snapshot_exception(
client_constructor, default_engine_client
):
grpc_client = _setup_client_mock(client_constructor)
grpc_client.get_quantum_processor_config.side_effect = exceptions.BadRequest('invalid_reueust')

with pytest.raises(EngineException, match='invalid_reueust'):
_ = default_engine_client.get_quantum_processor_config_from_snapshot(
project_id="test_project_id",
processor_id="test_processor_id",
config_name="test_config_name",
snapshot_id="test_snapshot_id",
)


@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_get_quantum_processor_config_from_run(client_constructor, default_engine_client):

project_id = "test_project_id"
processor_id = "test_processor_id"
run_name = "test_run_name"
config_name = "test_config_name"
resource_name = (
f'projects/{project_id}/'
f'processors/{processor_id}/'
f'configAutomationRuns/{run_name}/'
f'configs/{config_name}'
)

grpc_client = _setup_client_mock(client_constructor)
expected_result = quantum.QuantumProcessorConfig(name=resource_name)
grpc_client.get_quantum_processor_config.return_value = expected_result

actual_result = default_engine_client.get_quantum_processor_config_from_run(
project_id=project_id, processor_id=processor_id, config_name=config_name, run_name=run_name
)
grpc_client.get_quantum_processor_config.assert_called_with(
quantum.GetQuantumProcessorConfigRequest(name=resource_name)
)
assert actual_result == expected_result


@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_get_quantum_processor_config_from_run_not_found(client_constructor, default_engine_client):
project_id = "test_project_id"
processor_id = "test_processor_id"
run_name = "test_run_name"
config_name = "test_config_name"
resource_name = (
f'projects/{project_id}/'
f'processors/{processor_id}/'
f'configAutomationRuns/{run_name}/'
f'configs/{config_name}'
)
grpc_client = _setup_client_mock(client_constructor)
grpc_client.get_quantum_processor_config.side_effect = exceptions.NotFound('not found')

actual_result = default_engine_client.get_quantum_processor_config_from_run(
project_id=project_id, processor_id=processor_id, config_name=config_name, run_name=run_name
)
grpc_client.get_quantum_processor_config.assert_called_with(
quantum.GetQuantumProcessorConfigRequest(name=resource_name)
)
assert actual_result is None


@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_get_quantum_processor_config_from_run_exception(client_constructor, default_engine_client):
grpc_client = _setup_client_mock(client_constructor)
grpc_client.get_quantum_processor_config.side_effect = exceptions.BadRequest('invalid_reueust')

with pytest.raises(EngineException, match='invalid_reueust'):
_ = default_engine_client.get_quantum_processor_config_from_run(
project_id="test_project_id",
processor_id="test_processor_id",
config_name="test_config_name",
run_name="test_run_name",
)
Loading
Loading