Skip to content

Commit 413a7f5

Browse files
author
Jose Urruticoechea
committed
Add new processor_selector arguments in engine_client
1 parent bb7a92c commit 413a7f5

File tree

2 files changed

+146
-13
lines changed

2 files changed

+146
-13
lines changed

cirq-google/cirq_google/engine/engine_client.py

Lines changed: 54 additions & 12 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,25 @@ 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: 'processor_ids' in kwargs or len(args) > 3,
381+
)
375382
async def create_job_async(
376383
self,
377384
project_id: str,
378385
program_id: str,
379386
job_id: Optional[str],
380-
processor_ids: Sequence[str],
381-
run_context: any_pb2.Any,
387+
processor_ids: Optional[Sequence[str]] = None,
388+
run_context: any_pb2.Any = any_pb2.Any(),
382389
priority: Optional[int] = None,
383390
description: Optional[str] = None,
384391
labels: Optional[Dict[str, str]] = None,
392+
processor_id: Optional[str] = None,
393+
run_name: str = "",
394+
device_config_name: str = "",
385395
) -> Tuple[str, quantum.QuantumJob]:
386396
"""Creates and runs a job on Quantum Engine.
387397
@@ -390,33 +400,64 @@ async def create_job_async(
390400
program_id: Unique ID of the program within the parent project.
391401
job_id: Unique ID of the job within the parent program.
392402
run_context: Properly serialized run context.
393-
processor_ids: List of processor id for running the program.
403+
processor_ids: Deprecated list of processor ids for running the program.
404+
`processor_id` should be used instead.
394405
priority: Optional priority to run at, 0-1000.
395406
description: Optional description to set on the job.
396407
labels: Optional set of labels to set on the job.
408+
processor_id: Processor id for running the program. If not set,
409+
`processor_ids` will be used.
410+
run_name: A unique identifier representing an automation run for the
411+
specified processor (given by `processor_id`). An Automation Run contains a
412+
collection of device configurations for a processor.
413+
device_config_name: Configuration identifier used to identify a processor configuration
414+
within the automation run.
397415
398416
Returns:
399417
Tuple of created job id and job.
400418
401419
Raises:
402420
ValueError: If the priority is not between 0 and 1000.
421+
ValueError: If `processor_ids` and `processor_id` are both set.
422+
ValueError: If either `run_name` and `device_config_name` are set but
423+
`processor_id` is empty.
424+
ValueError: If `run_name` is set but `device_config_name` is empty.
403425
"""
404426
# Check program to run and program parameters.
405427
if priority and not 0 <= priority < 1000:
406428
raise ValueError('priority must be between 0 and 1000')
429+
if processor_id and processor_ids:
430+
raise ValueError(
431+
'`processor_ids` and `processor_id` cannot both be set.'
432+
'Please just use `processor_id` instead.'
433+
)
434+
if not processor_id and (run_name or device_config_name):
435+
raise ValueError(
436+
'Cannot specify `run_name` or `device_config_name` if `processor_id` is empty.'
437+
)
438+
if run_name and not device_config_name:
439+
raise ValueError('Must specify `device_config_name` if `run_name` is set')
407440

408441
# Create job.
442+
processor_selector = (
443+
quantum.SchedulingConfig.ProcessorSelector(
444+
processor=_processor_name_from_ids(project_id, processor_id),
445+
device_config_key=quantum.DeviceConfigKey(
446+
run_name=run_name, config_alias=device_config_name
447+
),
448+
)
449+
if processor_id
450+
else quantum.SchedulingConfig.ProcessorSelector(
451+
processor_names=[
452+
_processor_name_from_ids(project_id, processor_id)
453+
for processor_id in processor_ids
454+
]
455+
)
456+
)
409457
job_name = _job_name_from_ids(project_id, program_id, job_id) if job_id else ''
410458
job = quantum.QuantumJob(
411459
name=job_name,
412-
scheduling_config=quantum.SchedulingConfig(
413-
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-
]
418-
)
419-
),
460+
scheduling_config=quantum.SchedulingConfig(processor_selector=processor_selector),
420461
run_context=run_context,
421462
)
422463
if priority:
@@ -431,7 +472,8 @@ async def create_job_async(
431472
job = await self._send_request_async(self.grpc_client.create_quantum_job, request)
432473
return _ids_from_job_name(job.name)[2], job
433474

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

436478
async def list_jobs_async(
437479
self,

cirq-google/cirq_google/engine/engine_client_test.py

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"""Tests for EngineClient."""
1515
import asyncio
1616
import datetime
17+
import os
1718
from unittest import mock
1819

1920
import duet
@@ -23,6 +24,7 @@
2324
from google.protobuf.field_mask_pb2 import FieldMask
2425
from google.protobuf.timestamp_pb2 import Timestamp
2526

27+
import cirq
2628
from cirq_google.engine.engine_client import EngineClient, EngineException
2729
from cirq_google.cloud import quantum
2830

@@ -341,8 +343,9 @@ def test_delete_program(client_constructor):
341343
)
342344

343345

346+
@mock.patch.dict(os.environ, clear='CIRQ_TESTING')
344347
@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
345-
def test_create_job(client_constructor):
348+
def test_create_job_with_legacy_processor_ids(client_constructor):
346349
grpc_client = setup_mock_(client_constructor)
347350

348351
result = quantum.QuantumJob(name='projects/proj/programs/prog/jobs/job0')
@@ -467,6 +470,94 @@ def test_create_job(client_constructor):
467470
)
468471

469472

473+
@mock.patch.dict(os.environ, clear='CIRQ_TESTING')
474+
@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
475+
def test_create_job_with_run_name_and_device_config_name_and_no_processor_id_throws(
476+
client_constructor,
477+
):
478+
grpc_client = setup_mock_(client_constructor)
479+
result = quantum.QuantumJob(name='projects/proj/programs/prog/jobs/job0')
480+
grpc_client.create_quantum_job.return_value = result
481+
run_context = any_pb2.Any()
482+
client = EngineClient()
483+
484+
with pytest.raises(
485+
ValueError,
486+
match="Cannot specify `run_name` or `device_config_name` if `processor_id` is empty",
487+
):
488+
client.create_job(
489+
project_id='proj',
490+
program_id='prog',
491+
job_id=None,
492+
processor_ids=['processor0'],
493+
run_name="RUN_NAME",
494+
device_config_name="device_config_name",
495+
run_context=run_context,
496+
)
497+
498+
499+
@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
500+
def test_create_job_with_run_name_and_no_device_config_name_throws(client_constructor):
501+
grpc_client = setup_mock_(client_constructor)
502+
result = quantum.QuantumJob(name='projects/proj/programs/prog/jobs/job0')
503+
grpc_client.create_quantum_job.return_value = result
504+
run_context = any_pb2.Any()
505+
client = EngineClient()
506+
507+
with pytest.raises(ValueError, match="Must specify `device_config_name` if `run_name` is set"):
508+
client.create_job(
509+
project_id='proj',
510+
program_id='prog',
511+
job_id=None,
512+
processor_id='processor0',
513+
run_name="RUN_NAME",
514+
run_context=run_context,
515+
)
516+
517+
518+
@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
519+
@pytest.mark.parametrize(
520+
'run_name, device_config_name', [('RUN_NAME', 'CONFIG_NAME'), ('', 'CONFIG_NAME'), ('', '')]
521+
)
522+
def test_create_job_with_run_name_and_device_config_name(
523+
client_constructor, run_name, device_config_name
524+
):
525+
grpc_client = setup_mock_(client_constructor)
526+
result = quantum.QuantumJob(name='projects/proj/programs/prog/jobs/job0')
527+
grpc_client.create_quantum_job.return_value = result
528+
run_context = any_pb2.Any()
529+
client = EngineClient()
530+
531+
assert client.create_job(
532+
project_id='proj',
533+
program_id='prog',
534+
job_id='job0',
535+
processor_id='processor0',
536+
run_name=run_name,
537+
device_config_name=device_config_name,
538+
run_context=run_context,
539+
priority=10,
540+
) == ('job0', result)
541+
grpc_client.create_quantum_job.assert_called_with(
542+
quantum.CreateQuantumJobRequest(
543+
parent='projects/proj/programs/prog',
544+
quantum_job=quantum.QuantumJob(
545+
name='projects/proj/programs/prog/jobs/job0',
546+
run_context=run_context,
547+
scheduling_config=quantum.SchedulingConfig(
548+
priority=10,
549+
processor_selector=quantum.SchedulingConfig.ProcessorSelector(
550+
processor='projects/proj/processors/processor0',
551+
device_config_key=quantum.DeviceConfigKey(
552+
run_name=run_name, config_alias=device_config_name
553+
),
554+
),
555+
),
556+
),
557+
)
558+
)
559+
560+
470561
@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
471562
def test_get_job(client_constructor):
472563
grpc_client = setup_mock_(client_constructor)

0 commit comments

Comments
 (0)