Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion cirq-ionq/cirq_ionq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@

from cirq_ionq.sampler import Sampler as Sampler

from cirq_ionq.serializer import Serializer as Serializer, SerializedProgram as SerializedProgram
from cirq_ionq.serializer import (
QISSerializer as QISSerializer,
SerializedQISProgram as SerializedQISProgram,
SerializedOpenQASMProgram as SerializedOpenQASMProgram,
)

from cirq_ionq.service import Service as Service

Expand Down
34 changes: 25 additions & 9 deletions cirq-ionq/cirq_ionq/ionq_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import cirq_ionq
from cirq import __version__ as cirq_version
from cirq_ionq import ionq_exceptions
from cirq_ionq.ionq_exceptions import IonQNotSupportedMultipleCircuitsJobException

# https://support.cloudflare.com/hc/en-us/articles/115003014512-4xx-Client-Error
# "Cloudflare will generate and serve a 409 response for a Error 1001: DNS Resolution Error."
Expand Down Expand Up @@ -111,7 +112,7 @@ def __init__(

def create_job(
self,
serialized_program: cirq_ionq.SerializedProgram,
serialized_program: cirq_ionq.SerializedQISProgram | cirq_ionq.SerializedOpenQASMProgram,
repetitions: int | None = None,
target: str | None = None,
name: str | None = None,
Expand All @@ -121,8 +122,8 @@ def create_job(
"""Create a job.

Args:
serialized_program: The `cirq_ionq.SerializedProgram` containing the serialized
information about the circuit to run.
serialized_program: The `cirq_ionq.SerializedQISProgram` or `cirq_ionq.SerializedOpenQASMProgram`
containing the serialized information about the circuit to run.
repetitions: The number of times to repeat the circuit. For simulation the repeated
sampling is not done on the server, but is passed as metadata to be recovered
from the returned job.
Expand All @@ -141,12 +142,27 @@ def create_job(
"""
actual_target = self._target(target)

json: dict[str, Any] = {
'backend': actual_target,
"type": "ionq.multi-circuit.v1" if batch_mode else "ionq.circuit.v1",
'lang': 'json',
'input': serialized_program.input,
}
if isinstance(serialized_program, cirq_ionq.SerializedQISProgram):
json: dict[str, Any] = {
'backend': actual_target,
"type": "ionq.multi-circuit.v1" if batch_mode else "ionq.circuit.v1",
'lang': 'json',
'input': serialized_program.input,
}
elif isinstance(serialized_program, cirq_ionq.SerializedOpenQASMProgram):
if batch_mode:
raise IonQNotSupportedMultipleCircuitsJobException(
"Mid-circuit measurement, reset, and classical control flow are "
"only supported for single-circuit submissions. Submit such "
"circuits in separate jobs."
)
json: dict[str, Any] = {
'backend': actual_target,
"type": "ionq.qasm3.v1",
'lang': 'json',
'input': serialized_program.input,
}

if name:
json['name'] = name
# We have to pass measurement keys through the metadata.
Expand Down
28 changes: 14 additions & 14 deletions cirq-ionq/cirq_ionq/ionq_client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def test_ionq_client_create_job(mock_post):
mock_post.return_value.json.return_value = {'foo': 'bar'}

client = ionq.ionq_client._IonQClient(remote_host='http://example.com', api_key='to_my_heart')
program = ionq.SerializedProgram(
program = ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={'a': '0,1'},
settings={'aaa': 'bb'},
Expand Down Expand Up @@ -145,7 +145,7 @@ def test_ionq_client_create_job_error_mitigation_is_correctly_initialized(mock_p
mock_post.return_value.json.return_value = {'foo': 'bar'}

client = ionq.ionq_client._IonQClient(remote_host='http://example.com', api_key='to_my_heart')
program = ionq.SerializedProgram(
program = ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={'a': '0,1'},
settings={},
Expand Down Expand Up @@ -190,7 +190,7 @@ def test_ionq_client_create_job_compilation_is_correctly_initialized(mock_post):
mock_post.return_value.json.return_value = {'foo': 'bar'}

client = ionq.ionq_client._IonQClient(remote_host='http://example.com', api_key='to_my_heart')
program = ionq.SerializedProgram(
program = ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={'a': '0,1'},
settings={},
Expand Down Expand Up @@ -235,7 +235,7 @@ def test_ionq_client_create_job_extra_params(mock_post):
mock_post.return_value.json.return_value = {'foo': 'bar'}

client = ionq.ionq_client._IonQClient(remote_host='http://example.com', api_key='to_my_heart')
program = ionq.SerializedProgram(
program = ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={'a': '0,1'},
settings={},
Expand Down Expand Up @@ -278,7 +278,7 @@ def test_ionq_client_create_job_extra_params(mock_post):
def test_ionq_client_create_job_dry_run_warning_behavior(mock_post, target, expect_warning):

client = ionq.ionq_client._IonQClient(remote_host="http://example.com", api_key="to_my_heart")
program = ionq.SerializedProgram(
program = ionq.SerializedQISProgram(
input={"job": "mine"},
metadata={},
settings={},
Expand Down Expand Up @@ -308,7 +308,7 @@ def test_ionq_client_create_job_default_target(mock_post):
remote_host='http://example.com', api_key='to_my_heart', default_target='simulator'
)
_ = client.create_job(
ionq.SerializedProgram(
ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand All @@ -330,7 +330,7 @@ def test_ionq_client_create_job_target_overrides_default_target(mock_post):
remote_host='http://example.com', api_key='to_my_heart', default_target='simulator'
)
_ = client.create_job(
serialized_program=ionq.SerializedProgram(
serialized_program=ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand All @@ -349,7 +349,7 @@ def test_ionq_client_create_job_no_targets():
client = ionq.ionq_client._IonQClient(remote_host='http://example.com', api_key='to_my_heart')
with pytest.raises(AssertionError, match='neither were set'):
_ = client.create_job(
serialized_program=ionq.SerializedProgram(
serialized_program=ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand All @@ -371,7 +371,7 @@ def test_ionq_client_create_job_unauthorized(mock_post):
)
with pytest.raises(ionq.IonQException, match='Not authorized'):
_ = client.create_job(
serialized_program=ionq.SerializedProgram(
serialized_program=ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand All @@ -393,7 +393,7 @@ def test_ionq_client_create_job_not_found(mock_post):
)
with pytest.raises(ionq.IonQNotFoundException, match='not find'):
_ = client.create_job(
serialized_program=ionq.SerializedProgram(
serialized_program=ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand All @@ -415,7 +415,7 @@ def test_ionq_client_create_job_not_retriable(mock_post):
)
with pytest.raises(ionq.IonQException, match='Status: 409'):
_ = client.create_job(
serialized_program=ionq.SerializedProgram(
serialized_program=ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand Down Expand Up @@ -444,7 +444,7 @@ def test_ionq_client_create_job_retry(mock_post):
test_stdout = io.StringIO()
with contextlib.redirect_stdout(test_stdout):
_ = client.create_job(
serialized_program=ionq.SerializedProgram(
serialized_program=ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand All @@ -467,7 +467,7 @@ def test_ionq_client_create_job_retry_request_error(mock_post):
remote_host='http://example.com', api_key='to_my_heart', default_target='simulator'
)
_ = client.create_job(
serialized_program=ionq.SerializedProgram(
serialized_program=ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand All @@ -493,7 +493,7 @@ def test_ionq_client_create_job_timeout(mock_post):
)
with pytest.raises(TimeoutError):
_ = client.create_job(
serialized_program=ionq.SerializedProgram(
serialized_program=ionq.SerializedQISProgram(
input={'job': 'mine'},
metadata={},
settings={},
Expand Down
10 changes: 10 additions & 0 deletions cirq-ionq/cirq_ionq/ionq_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,13 @@ class NotSupportedPauliexpParameters(Exception):

def __init__(self, message):
super().__init__(f"Message: '{message}'")


class IonQNotSupportedMultipleCircuitsJobException(Exception):
"""An exception that is thrown when trying to send create a job
containing multiple circuits with mid-circuit measurements, resets,
or classical control flow.
"""

def __init__(self, message):
super().__init__(f"Message: '{message}'")
4 changes: 2 additions & 2 deletions cirq-ionq/cirq_ionq/json_test_data/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
packages=[cirq_ionq],
test_data_path=pathlib.Path(__file__).parent,
not_yet_serializable=[
"SerializedProgram",
"SerializedQISProgram",
"Calibration",
"QPUResult",
"IonQException",
Expand All @@ -36,7 +36,7 @@
"Job",
"SimulatorResult",
],
should_not_be_serialized=["Sampler", "Service", "Serializer"],
should_not_be_serialized=["Sampler", "Service", "QISSerializer"],
resolver_cache=_class_resolver_dictionary(),
deprecated={},
)
Loading
Loading