Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support the new quantum engine processor_selector in engine_client #6254

Merged
merged 18 commits into from
Aug 28, 2023
Merged
Prev Previous commit
Next Next commit
Address cxing comments
  • Loading branch information
Jose Urruticoechea committed Aug 25, 2023
commit 84fc2df6a88007d8b7a9bd3711e4be09b896f49d
49 changes: 30 additions & 19 deletions cirq-google/cirq_google/engine/engine_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,38 +408,25 @@ async def create_job_async(
processor_id: Processor id for running the program. If not set,
`processor_ids` will be used.
run_name: A unique identifier representing an automation run for the
jurruti marked this conversation as resolved.
Show resolved Hide resolved
specified processor (given by `processor_id`). An Automation Run contains a
collection of device configurations for a processor.
specified processor. An Automation Run contains a collection of
device configurations for a processor. If specified, `processor_id`
is required to be set.
device_config_name: Configuration identifier used to identify a processor configuration
within the automation run.

within the automation run. If specified, `processor_id` is required to be set.
jurruti marked this conversation as resolved.
Show resolved Hide resolved
Returns:
Tuple of created job id and job.

Raises:
ValueError: If the priority is not between 0 and 1000.
ValueError: If `processor_ids` and `processor_id` are both set.
ValueError: If neither `processor_ids` or `processor_id` are set.
ValueError: If exactly one of `processor_ids` and `processor_id` is not set.
ValueError: If either `run_name` and `device_config_name` are set but
`processor_id` is empty.
ValueError: If `run_name` is set but `device_config_name` is empty.
"""
# Check program to run and program parameters.
if priority and not 0 <= priority < 1000:
raise ValueError('priority must be between 0 and 1000')
if processor_id and processor_ids:
raise ValueError(
'`processor_ids` and `processor_id` cannot both be set.'
'Please just use `processor_id` instead.'
)
if not processor_id and not processor_ids:
raise ValueError('`processor_id` must be set.')
if not processor_id and (run_name or device_config_name):
raise ValueError(
'Cannot specify `run_name` or `device_config_name` if `processor_id` is empty.'
)
if bool(run_name) ^ bool(device_config_name):
raise ValueError('Cannot specify only one of `run_name` and `device_config_name`')
_validate_create_job_processor_and_config_selection(processor_ids, processor_id, run_name, device_config_name)

# Create job.
processor_selector = (
Expand Down Expand Up @@ -1136,3 +1123,27 @@ def _date_or_time_to_filter_expr(param_name: str, param: Union[datetime.datetime
f"type {type(param)}. Supported types: datetime.datetime and"
f"datetime.date"
)

def _validate_create_job_processor_and_config_selection(
processor_ids: Optional[Sequence[str]],
processor_id: str,
run_name: str,
device_config_name: str,
):
""" Validates create job arguments that select the processor and device configuration
Raises:
ValueError: If exactly one of `processor_ids` and `processor_id` is not set.
ValueError: If either `run_name` and `device_config_name` are set but
`processor_id` is empty.
ValueError: If `run_name` is set but `device_config_name` is empty.
"""
if not (bool(processor_id) ^ bool(processor_ids)):
raise ValueError(
'Exactly one of `processor_ids` and `processor_id` must be set'
)
if not processor_id and (run_name or device_config_name):
raise ValueError(
'Cannot specify `run_name` or `device_config_name` if `processor_id` is empty.'
)
if bool(run_name) ^ bool(device_config_name):
raise ValueError('Cannot specify only one of `run_name` and `device_config_name`')
81 changes: 14 additions & 67 deletions cirq-google/cirq_google/engine/engine_client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,90 +468,37 @@ def test_create_job_with_legacy_processor_ids(client_constructor):
priority=5000,
)


@mock.patch.dict(os.environ, clear='CIRQ_TESTING')
@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_create_job_with_run_name_and_device_config_name_and_no_processor_id_throws(
client_constructor,
@pytest.mark.parametrize(
'processor_ids, processor_id, run_name, device_config_name, error_message',
[
(['processor0'], '', 'RUN_NAME', 'CONFIG_ALIAS', 'Cannot specify `run_name` or `device_config_name` if `processor_id` is empty'),
(['processor0'], 'processor0', '', '', 'Exactly one of `processor_ids` and `processor_id` must be set'),
(None, '', '', '', 'Exactly one of `processor_ids` and `processor_id` must be set'),
(None, 'processor0', 'RUN_NAME', '', 'Cannot specify only one of `run_name` and `device_config_name`'),
(None, 'processor0', '', 'CONFIG_ALIAS', 'Cannot specify only one of `run_name` and `device_config_name`')
])
def test_create_job_with_invalid_processor_and_device_config_arguments_throw(
client_constructor, processor_ids, processor_id, run_name, device_config_name, error_message
):
grpc_client = setup_mock_(client_constructor)
result = quantum.QuantumJob(name='projects/proj/programs/prog/jobs/job0')
grpc_client.create_quantum_job.return_value = result
run_context = any_pb2.Any()
client = EngineClient()

with pytest.raises(
ValueError,
match="Cannot specify `run_name` or `device_config_name` if `processor_id` is empty",
):
client.create_job(
project_id='proj',
program_id='prog',
job_id=None,
processor_ids=['processor0'],
run_name="RUN_NAME",
device_config_name="device_config_name",
run_context=run_context,
)


@mock.patch.dict(os.environ, clear='CIRQ_TESTING')
@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_create_job_with_processor_id_and_processor_ids_throws(client_constructor):
grpc_client = setup_mock_(client_constructor)
result = quantum.QuantumJob(name='projects/proj/programs/prog/jobs/job0')
grpc_client.create_quantum_job.return_value = result
run_context = any_pb2.Any()
client = EngineClient()

with pytest.raises(ValueError, match="`processor_ids` and `processor_id` cannot both be set"):
client.create_job(
project_id='proj',
program_id='prog',
job_id=None,
processor_id='processor0',
processor_ids=['processor0'],
run_context=run_context,
)


@mock.patch.dict(os.environ, clear='CIRQ_TESTING')
@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
def test_create_job_with_no_processor_id_throws(client_constructor):
grpc_client = setup_mock_(client_constructor)
result = quantum.QuantumJob(name='projects/proj/programs/prog/jobs/job0')
grpc_client.create_quantum_job.return_value = result
run_context = any_pb2.Any()
client = EngineClient()

with pytest.raises(ValueError, match="`processor_id` must be set."):
client.create_job(
project_id='proj', program_id='prog', job_id=None, run_context=run_context
)


@mock.patch.object(quantum, 'QuantumEngineServiceAsyncClient', autospec=True)
@pytest.mark.parametrize('run_name, device_config_name', [('RUN_NAME', ''), ('', 'CONFIG_NAME')])
def test_create_job_with_incomplete_device_config_throws(
client_constructor, run_name, device_config_name
):
grpc_client = setup_mock_(client_constructor)
result = quantum.QuantumJob(name='projects/proj/programs/prog/jobs/job0')
grpc_client.create_quantum_job.return_value = result
run_context = any_pb2.Any()
client = EngineClient()

with pytest.raises(
ValueError, match="Cannot specify only one of `run_name` and `device_config_name`"
match=error_message,
):
client.create_job(
project_id='proj',
program_id='prog',
job_id=None,
processor_id='processor0',
processor_ids=processor_ids,
processor_id=processor_id,
run_name=run_name,
device_config_name=device_config_name,
run_context=run_context,
)


Expand Down