Skip to content

Commit 8bd2161

Browse files
jurrutiJose Urruticoechea
andauthored
Support the new quantum engine processor_selector in engine_client (#6254)
* Add DeviceConfigKey to Quantum Engine API types * Add new processor_selector arguments in engine_client * fix lint * change processor_id type * Add test coverage * Address cxing comments * fix formatting * fix raises docstrings * make new parameters to be mandatory keyword arguments * fix typo * Fix create_job deprecated arguments * fix format * small refactor * Address wcourtney comments --------- Co-authored-by: Jose Urruticoechea <urruti@google.com>
1 parent 56b5db2 commit 8bd2161

File tree

6 files changed

+234
-15
lines changed

6 files changed

+234
-15
lines changed

cirq-google/cirq_google/cloud/quantum/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from cirq_google.cloud.quantum_v1alpha1.types.engine import UpdateQuantumJobRequest
5858
from cirq_google.cloud.quantum_v1alpha1.types.engine import UpdateQuantumProgramRequest
5959
from cirq_google.cloud.quantum_v1alpha1.types.engine import UpdateQuantumReservationRequest
60+
from cirq_google.cloud.quantum_v1alpha1.types.quantum import DeviceConfigKey
6061
from cirq_google.cloud.quantum_v1alpha1.types.quantum import ExecutionStatus
6162
from cirq_google.cloud.quantum_v1alpha1.types.quantum import GcsLocation
6263
from cirq_google.cloud.quantum_v1alpha1.types.quantum import InlineData
@@ -115,6 +116,7 @@
115116
'UpdateQuantumJobRequest',
116117
'UpdateQuantumProgramRequest',
117118
'UpdateQuantumReservationRequest',
119+
'DeviceConfigKey',
118120
'ExecutionStatus',
119121
'GcsLocation',
120122
'InlineData',

cirq-google/cirq_google/cloud/quantum_v1alpha1/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from .types.engine import UpdateQuantumJobRequest
5858
from .types.engine import UpdateQuantumProgramRequest
5959
from .types.engine import UpdateQuantumReservationRequest
60+
from .types.quantum import DeviceConfigKey
6061
from .types.quantum import ExecutionStatus
6162
from .types.quantum import GcsLocation
6263
from .types.quantum import InlineData
@@ -84,6 +85,7 @@
8485
'DeleteQuantumJobRequest',
8586
'DeleteQuantumProgramRequest',
8687
'DeleteQuantumReservationRequest',
88+
'DeviceConfigKey',
8789
'ExecutionStatus',
8890
'GcsLocation',
8991
'GetQuantumCalibrationRequest',

cirq-google/cirq_google/cloud/quantum_v1alpha1/types/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
UpdateQuantumReservationRequest,
5757
)
5858
from .quantum import (
59+
DeviceConfigKey,
5960
ExecutionStatus,
6061
GcsLocation,
6162
InlineData,
@@ -114,6 +115,7 @@
114115
'UpdateQuantumJobRequest',
115116
'UpdateQuantumProgramRequest',
116117
'UpdateQuantumReservationRequest',
118+
'DeviceConfigKey',
117119
'ExecutionStatus',
118120
'GcsLocation',
119121
'InlineData',

cirq-google/cirq_google/cloud/quantum_v1alpha1/types/quantum.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,25 @@ class QuantumJob(proto.Message):
226226
)
227227

228228

229+
class DeviceConfigKey(proto.Message):
230+
r"""-
231+
Attributes:
232+
run_name (str):
233+
-
234+
config_alias (str):
235+
-
236+
"""
237+
238+
run_name = proto.Field(
239+
proto.STRING,
240+
number=1,
241+
)
242+
config_alias = proto.Field(
243+
proto.STRING,
244+
number=2,
245+
)
246+
247+
229248
class SchedulingConfig(proto.Message):
230249
r"""-
231250
@@ -244,12 +263,25 @@ class ProcessorSelector(proto.Message):
244263
Attributes:
245264
processor_names (Sequence[str]):
246265
-
266+
processor (str):
267+
-
268+
device_config_key ((google.cloud.quantum_v1alpha1.types.DeviceConfigKey):
269+
-
247270
"""
248271

249272
processor_names = proto.RepeatedField(
250273
proto.STRING,
251274
number=1,
252275
)
276+
processor = proto.Field(
277+
proto.STRING,
278+
number=2,
279+
)
280+
device_config_key = proto.Field(
281+
proto.MESSAGE,
282+
number=3,
283+
message=DeviceConfigKey
284+
)
253285

254286
target_route = proto.Field(
255287
proto.STRING,

cirq-google/cirq_google/engine/engine_client.py

Lines changed: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from google.protobuf.timestamp_pb2 import Timestamp
3737

3838
from cirq._compat import cached_property
39+
from cirq._compat import deprecated_parameter
3940
from cirq_google.cloud import quantum
4041
from cirq_google.engine.asyncio_executor import AsyncioExecutor
4142

@@ -372,16 +373,27 @@ async def delete_program_async(
372373

373374
delete_program = duet.sync(delete_program_async)
374375

376+
@deprecated_parameter(
377+
deadline='v1.4',
378+
fix='Use `processor_id` instead of `processor_ids`.',
379+
parameter_desc='processor_ids',
380+
match=lambda args, kwargs: _match_deprecated_processor_ids(args, kwargs),
381+
rewrite=lambda args, kwargs: rewrite_processor_ids_to_processor_id(args, kwargs),
382+
)
375383
async def create_job_async(
376384
self,
377385
project_id: str,
378386
program_id: str,
379387
job_id: Optional[str],
380-
processor_ids: Sequence[str],
381-
run_context: any_pb2.Any,
388+
processor_ids: Optional[Sequence[str]] = None,
389+
run_context: any_pb2.Any = any_pb2.Any(),
382390
priority: Optional[int] = None,
383391
description: Optional[str] = None,
384392
labels: Optional[Dict[str, str]] = None,
393+
*,
394+
processor_id: str = "",
395+
run_name: str = "",
396+
device_config_name: str = "",
385397
) -> Tuple[str, quantum.QuantumJob]:
386398
"""Creates and runs a job on Quantum Engine.
387399
@@ -390,31 +402,53 @@ async def create_job_async(
390402
program_id: Unique ID of the program within the parent project.
391403
job_id: Unique ID of the job within the parent program.
392404
run_context: Properly serialized run context.
393-
processor_ids: List of processor id for running the program.
405+
processor_ids: Deprecated list of processor ids for running the program.
406+
Only allowed to contain one processor_id. If the argument `processor_id`
407+
is non-empty, `processor_ids` will be ignored. Otherwise the deprecated
408+
decorator will fix the arguments and call create_job_async using
409+
`processor_id` instead of `processor_ids`.
394410
priority: Optional priority to run at, 0-1000.
395411
description: Optional description to set on the job.
396412
labels: Optional set of labels to set on the job.
397-
413+
processor_id: Processor id for running the program. If not set,
414+
`processor_ids` will be used.
415+
run_name: A unique identifier representing an automation run for the
416+
specified processor. An Automation Run contains a collection of
417+
device configurations for a processor. If specified, `processor_id`
418+
is required to be set.
419+
device_config_name: An identifier used to select the processor configuration
420+
utilized to run the job. A configuration identifies the set of
421+
available qubits, couplers, and supported gates in the processor.
422+
If specified, `processor_id` is required to be set.
398423
Returns:
399424
Tuple of created job id and job.
400425
401426
Raises:
402427
ValueError: If the priority is not between 0 and 1000.
428+
ValueError: If neither `processor_id` or `processor_ids` are set.
429+
ValueError: If only one of `run_name` and `device_config_name` are specified.
430+
ValueError: If `processor_ids` has more than one processor id.
431+
ValueError: If either `run_name` and `device_config_name` are set but
432+
`processor_id` is empty.
403433
"""
404434
# Check program to run and program parameters.
405435
if priority and not 0 <= priority < 1000:
406436
raise ValueError('priority must be between 0 and 1000')
437+
if not processor_id:
438+
raise ValueError('Must specify a processor id when creating a job.')
439+
if bool(run_name) ^ bool(device_config_name):
440+
raise ValueError('Cannot specify only one of `run_name` and `device_config_name`')
407441

408442
# Create job.
409443
job_name = _job_name_from_ids(project_id, program_id, job_id) if job_id else ''
410444
job = quantum.QuantumJob(
411445
name=job_name,
412446
scheduling_config=quantum.SchedulingConfig(
413447
processor_selector=quantum.SchedulingConfig.ProcessorSelector(
414-
processor_names=[
415-
_processor_name_from_ids(project_id, processor_id)
416-
for processor_id in processor_ids
417-
]
448+
processor=_processor_name_from_ids(project_id, processor_id),
449+
device_config_key=quantum.DeviceConfigKey(
450+
run_name=run_name, config_alias=device_config_name
451+
),
418452
)
419453
),
420454
run_context=run_context,
@@ -431,7 +465,8 @@ async def create_job_async(
431465
job = await self._send_request_async(self.grpc_client.create_quantum_job, request)
432466
return _ids_from_job_name(job.name)[2], job
433467

434-
create_job = duet.sync(create_job_async)
468+
# TODO(cxing): Remove type ignore once @deprecated_parameter decorator is removed
469+
create_job = duet.sync(create_job_async) # type: ignore
435470

436471
async def list_jobs_async(
437472
self,
@@ -1090,3 +1125,40 @@ def _date_or_time_to_filter_expr(param_name: str, param: Union[datetime.datetime
10901125
f"type {type(param)}. Supported types: datetime.datetime and"
10911126
f"datetime.date"
10921127
)
1128+
1129+
1130+
def rewrite_processor_ids_to_processor_id(args, kwargs):
1131+
"""Rewrites the create_job parameters so that `processor_id` is used instead of the deprecated
1132+
`processor_ids`.
1133+
1134+
Raises:
1135+
ValueError: If `processor_ids` has more than one processor id.
1136+
ValueError: If `run_name` or `device_config_name` are set but `processor_id` is not.
1137+
"""
1138+
1139+
# Use `processor_id` keyword argument instead of `processor_ids`
1140+
processor_ids = args[4] if len(args) > 4 else kwargs['processor_ids']
1141+
if len(processor_ids) > 1:
1142+
raise ValueError("The use of multiple processors is no longer supported.")
1143+
if 'processor_id' not in kwargs or not kwargs['processor_id']:
1144+
if ('run_name' in kwargs and kwargs['run_name']) or (
1145+
'device_config_name' in kwargs and kwargs['device_config_name']
1146+
):
1147+
raise ValueError(
1148+
'Cannot specify `run_name` or `device_config_name` if `processor_id` is empty.'
1149+
)
1150+
kwargs['processor_id'] = processor_ids[0]
1151+
1152+
# Erase `processor_ids` from args and kwargs
1153+
if len(args) > 4:
1154+
args_list = list(args)
1155+
args_list[4] = None
1156+
args = tuple(args_list)
1157+
else:
1158+
kwargs.pop('processor_ids')
1159+
1160+
return args, kwargs
1161+
1162+
1163+
def _match_deprecated_processor_ids(args, kwargs):
1164+
return ('processor_ids' in kwargs and kwargs['processor_ids']) or len(args) > 4

0 commit comments

Comments
 (0)