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

Ability to pass in options to SuperstaqProvider and Service #708

Merged
merged 36 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ceb1611
add noise customization to aces
epelaaez Aug 15, 2023
dfd58ae
typo
epelaaez Aug 15, 2023
ee93c59
add support for cirq noise models
epelaaez Aug 15, 2023
8d32585
move aces to SuperstaqProvider
epelaaez Aug 16, 2023
1ce9fb8
pass optional arguments to json dict iff given
epelaaez Aug 16, 2023
a63e077
Pass options in providers
vtomole Aug 21, 2023
b5e6fd2
Documentation
vtomole Aug 21, 2023
281a0c1
Remove unneccesary types
vtomole Aug 22, 2023
a516aa2
Park
vtomole Aug 22, 2023
dc8a56e
Kwargs
vtomole Aug 24, 2023
a60cdfa
Merge branch 'main' into pass_options_to_get
vtomole Aug 24, 2023
e7d357a
Update general-superstaq/general_superstaq/superstaq_client.py
vtomole Aug 25, 2023
d0ff6d0
Update general-superstaq/general_superstaq/superstaq_client.py
vtomole Aug 25, 2023
fdec3cb
Update general-superstaq/general_superstaq/superstaq_client.py
vtomole Aug 25, 2023
131eb62
Update cirq-superstaq/cirq_superstaq/service.py
vtomole Aug 25, 2023
d9aa311
Merge branch 'main' into aces-noise
epelaaez Aug 29, 2023
a94de3c
reorder methods
epelaaez Aug 23, 2023
56b13c4
reviews
epelaaez Aug 24, 2023
32abf0b
remove extra check
epelaaez Aug 24, 2023
101768c
code review
epelaaez Aug 28, 2023
33f2a56
error prob bullet points
epelaaez Aug 29, 2023
63d4457
make integration test use cirq noise model
epelaaez Aug 29, 2023
0d58c9e
Update qiskit-superstaq/qiskit_superstaq/daily_integration_test.py
epelaaez Aug 30, 2023
19ed42e
Update general-superstaq/general_superstaq/superstaq_client.py
vtomole Aug 30, 2023
119b362
Merge branch 'main' into pass_options_to_get
vtomole Aug 30, 2023
8db0f52
Remove deprecation warnings
vtomole Aug 30, 2023
6315192
Merge branch 'pass_options_to_get' of github.com:Infleqtion/client-su…
vtomole Aug 30, 2023
32e7f1c
Merge branch 'main' into pass_options_to_get
vtomole Aug 31, 2023
c9def68
Remove tags in find_jobs
vtomole Aug 31, 2023
56d1b12
Merge branch 'pass_options_to_get' of github.com:Infleqtion/client-su…
vtomole Aug 31, 2023
ca42929
Update general-superstaq/general_superstaq/superstaq_client.py
vtomole Aug 31, 2023
803b102
Update general-superstaq/general_superstaq/superstaq_client_test.py
vtomole Aug 31, 2023
0a430e4
Update general-superstaq/general_superstaq/superstaq_client_test.py
vtomole Aug 31, 2023
7a02190
Update general-superstaq/general_superstaq/superstaq_client_test.py
vtomole Aug 31, 2023
3dce0e5
Kwargs docstring
vtomole Aug 31, 2023
7d8ee98
Update general-superstaq/general_superstaq/superstaq_client_test.py
vtomole Aug 31, 2023
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
8 changes: 6 additions & 2 deletions cirq-superstaq/cirq_superstaq/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def __init__(
api_version: str = gss.API_VERSION,
max_retry_seconds: int = 3600,
verbose: bool = False,
**kwargs: Any,
vtomole marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
"""Creates the Service to access Superstaq's API.

Expand All @@ -142,19 +143,23 @@ def __init__(
api_version: Version of the api.
max_retry_seconds: The number of seconds to retry calls for. Defaults to one hour.
verbose: Whether to print to stdio and stderr on retriable errors.
kwargs: Other optimization and execution parameters.
- qiskit_pulse: Whether to use Superstaq's pulse-level optimizations for IBMQ
devices.
- cq_token: Token from CQ cloud.

Raises:
EnvironmentError: If an API key was not provided and could not be found.
"""
self.default_target = default_target

self._client = superstaq_client._SuperstaqClient(
client_name="cirq-superstaq",
remote_host=remote_host,
api_key=api_key,
api_version=api_version,
max_retry_seconds=max_retry_seconds,
verbose=verbose,
**kwargs,
)

def _resolve_target(self, target: Union[str, None]) -> str:
Expand Down Expand Up @@ -270,7 +275,6 @@ def create_job(
serialized_circuits = css.serialization.serialize_circuits(circuit)

target = self._resolve_target(target)

result = self._client.create_job(
serialized_circuits={"cirq_circuits": serialized_circuits},
repetitions=repetitions,
Expand Down
64 changes: 60 additions & 4 deletions general-superstaq/general_superstaq/superstaq_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import textwrap
import time
import urllib
import warnings
from typing import Any, Callable, Dict, List, Optional, Union

import qubovert as qv
Expand Down Expand Up @@ -48,6 +49,7 @@ def __init__(
api_version: str = gss.API_VERSION,
max_retry_seconds: float = 60, # 1 minute
verbose: bool = False,
**kwargs: Any,
):
"""Creates the SuperstaqClient.

Expand All @@ -66,6 +68,10 @@ def __init__(
which is the most recent version when this client was downloaded.
max_retry_seconds: The time to continue retriable responses. Defaults to 3600.
verbose: Whether to print to stderr and stdio any retriable errors that are encountered.
kwargs: Other optimization and execution parameters.
vtomole marked this conversation as resolved.
Show resolved Hide resolved
- qiskit_pulse: Whether to use Superstaq's pulse-level optimizations for IBMQ
devices.
- cq_token: Token from CQ cloud.
"""

self.api_key = api_key or gss.superstaq_client.find_api_key()
Expand Down Expand Up @@ -93,6 +99,7 @@ def __init__(
"X-Client-Name": self.client_name,
"X-Client-Version": self.api_version,
}
self._client_kwargs = kwargs

def get_request(self, endpoint: str) -> Any:
"""Performs a GET request on a given endpoint.
Expand Down Expand Up @@ -193,12 +200,19 @@ def create_job(
"target": target,
"shots": int(repetitions),
}

if method is not None:
json_dict["method"] = method
if kwargs or self._client_kwargs:
json_dict["options"] = json.dumps({**kwargs, **self._client_kwargs})
vtomole marked this conversation as resolved.
Show resolved Hide resolved
if "cq_token" in json_dict["options"]:
vtomole marked this conversation as resolved.
Show resolved Hide resolved
warnings.warn(
"Starting with client-superstaq v0.4.20, passing in `cq_token` when "
vtomole marked this conversation as resolved.
Show resolved Hide resolved
"submitting the job won't work. Pass `cq_token` when creating the provider "
"or service instead.",
DeprecationWarning,
stacklevel=2,
)

if kwargs:
json_dict["options"] = json.dumps(kwargs)
return self.post_request("/jobs", json_dict)

def get_job(self, job_id: str) -> Dict[str, str]:
Expand All @@ -213,7 +227,49 @@ def get_job(self, job_id: str) -> Dict[str, str]:
Raises:
SuperstaqServerException: For other API call failures.
"""
return self.get_request(f"/job/{job_id}")
warnings.warn(
"Starting with client-superstaq v0.4.20, the `get_job` method and "
vtomole marked this conversation as resolved.
Show resolved Hide resolved
"endpoint won't exist. Call `fetch_jobs` instead.",
DeprecationWarning,
stacklevel=2,
)
return self.fetch_jobs([job_id])[0]
vtomole marked this conversation as resolved.
Show resolved Hide resolved

def fetch_jobs(
self,
job_ids: List[str],
tags: Optional[List[str]] = None,
targets: Optional[List[str]] = None,
vtomole marked this conversation as resolved.
Show resolved Hide resolved
**kwargs: Any,
) -> List[Dict[str, str]]:
"""Get the job from the Superstaq API.

Args:
job_ids: The UUID of the job (returned when the job was created).
tags: optional tags of jobs
targets: optional targets of jobs
kwargs: Extra options needed to fetch jobs.
- cq_token: CQ Cloud credentials.

Returns:
The json body of the response as a dict.

Raises:
SuperstaqServerException: For other API call failures.
"""

json_dict: Dict[str, Any] = {
"job_ids": job_ids,
}

if tags:
json_dict["tags"] = tags
if targets:
json_dict["targets"] = targets
if kwargs or self._client_kwargs:
json_dict["options"] = json.dumps({**kwargs, **self._client_kwargs})
vtomole marked this conversation as resolved.
Show resolved Hide resolved

return self.post_request("/fetch_jobs", json_dict)

def get_balance(self) -> Dict[str, float]:
"""Get the querying user's account balance in USD.
Expand Down
80 changes: 47 additions & 33 deletions general-superstaq/general_superstaq/superstaq_client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,21 +152,26 @@ def test_supertstaq_client_create_job(mock_post: mock.MagicMock) -> None:
remote_host="http://example.com",
api_key="to_my_heart",
)
response = client.create_job(
serialized_circuits={"Hello": "World"},
repetitions=200,
target="ss_example_qpu",
method="dry-run",
qiskit_pulse=True,
)

with pytest.warns(DeprecationWarning):
response = client.create_job(
serialized_circuits={"Hello": "World"},
repetitions=200,
target="ss_example_qpu",
method="dry-run",
qiskit_pulse=True,
cq_token={"@type": "RefreshFlowState", "access_token": "123"},
)
assert response == {"foo": "bar"}

expected_json = {
"Hello": "World",
"target": "ss_example_qpu",
"shots": 200,
"method": "dry-run",
"options": json.dumps({"qiskit_pulse": True}),
"options": json.dumps(
{"qiskit_pulse": True, "cq_token": {"@type": "RefreshFlowState", "access_token": "123"}}
),
}
mock_post.assert_called_with(
f"http://example.com/{API_VERSION}/jobs",
Expand Down Expand Up @@ -287,20 +292,29 @@ def test_superstaq_client_create_job_json(mock_post: mock.MagicMock) -> None:
)


@mock.patch("requests.get")
def test_superstaq_client_get_job(mock_get: mock.MagicMock) -> None:
mock_get.return_value.ok = True
mock_get.return_value.json.return_value = {"foo": "bar"}
@mock.patch("requests.post")
def test_superstaq_client_fetch_jobs(mock_post: mock.MagicMock) -> None:
mock_post.return_value.ok = True
mock_post.return_value.json.return_value = [{"foo": "bar"}]
vtomole marked this conversation as resolved.
Show resolved Hide resolved
client = gss.superstaq_client._SuperstaqClient(
client_name="general-superstaq",
remote_host="http://example.com",
api_key="to_my_heart",
)
response = client.get_job(job_id="job_id")
assert response == {"foo": "bar"}

mock_get.assert_called_with(
f"http://example.com/{API_VERSION}/job/job_id", headers=EXPECTED_HEADERS, verify=False
response = client.fetch_jobs(
job_ids=["job_id"], tags=["tag"], targets=["targets"], cq_token="token"
)
assert response == [{"foo": "bar"}]
vtomole marked this conversation as resolved.
Show resolved Hide resolved
mock_post.assert_called_with(
f"http://example.com/{API_VERSION}/fetch_jobs",
json={
"job_ids": ["job_id"],
"tags": ["tag"],
"targets": ["targets"],
"options": '{"cq_token": "token"}',
vtomole marked this conversation as resolved.
Show resolved Hide resolved
},
headers=EXPECTED_HEADERS,
verify=False,
)


Expand Down Expand Up @@ -451,10 +465,10 @@ def test_superstaq_client_get_targets(mock_get: mock.MagicMock) -> None:
)


@mock.patch("requests.get")
def test_superstaq_client_get_job_unauthorized(mock_get: mock.MagicMock) -> None:
mock_get.return_value.ok = False
mock_get.return_value.status_code = requests.codes.unauthorized
@mock.patch("requests.post")
def test_superstaq_client_get_job_unauthorized(mock_post: mock.MagicMock) -> None:
mock_post.return_value.ok = False
mock_post.return_value.status_code = requests.codes.unauthorized

client = gss.superstaq_client._SuperstaqClient(
client_name="general-superstaq",
Expand All @@ -465,10 +479,10 @@ def test_superstaq_client_get_job_unauthorized(mock_get: mock.MagicMock) -> None
_ = client.get_job("job_id")


@mock.patch("requests.get")
def test_superstaq_client_get_job_not_found(mock_get: mock.MagicMock) -> None:
(mock_get.return_value).ok = False
(mock_get.return_value).status_code = requests.codes.not_found
@mock.patch("requests.post")
def test_superstaq_client_get_job_not_found(mock_post: mock.MagicMock) -> None:
(mock_post.return_value).ok = False
(mock_post.return_value).status_code = requests.codes.not_found

client = gss.superstaq_client._SuperstaqClient(
client_name="general-superstaq",
Expand All @@ -479,10 +493,10 @@ def test_superstaq_client_get_job_not_found(mock_get: mock.MagicMock) -> None:
_ = client.get_job("job_id")


@mock.patch("requests.get")
def test_superstaq_client_get_job_not_retriable(mock_get: mock.MagicMock) -> None:
mock_get.return_value.ok = False
mock_get.return_value.status_code = requests.codes.bad_request
@mock.patch("requests.post")
def test_superstaq_client_get_job_not_retriable(mock_post: mock.MagicMock) -> None:
mock_post.return_value.ok = False
mock_post.return_value.status_code = requests.codes.bad_request

client = gss.superstaq_client._SuperstaqClient(
client_name="general-superstaq",
Expand All @@ -493,11 +507,11 @@ def test_superstaq_client_get_job_not_retriable(mock_get: mock.MagicMock) -> Non
_ = client.get_job("job_id")


@mock.patch("requests.get")
def test_superstaq_client_get_job_retry(mock_get: mock.MagicMock) -> None:
@mock.patch("requests.post")
def test_superstaq_client_get_job_retry(mock_post: mock.MagicMock) -> None:
response1 = mock.MagicMock()
response2 = mock.MagicMock()
mock_get.side_effect = [response1, response2]
mock_post.side_effect = [response1, response2]
response1.ok = False
response1.status_code = requests.codes.service_unavailable
response2.ok = True
Expand All @@ -507,7 +521,7 @@ def test_superstaq_client_get_job_retry(mock_get: mock.MagicMock) -> None:
api_key="to_my_heart",
)
_ = client.get_job("job_id")
assert mock_get.call_count == 2
assert mock_post.call_count == 2


@mock.patch("requests.post")
Expand Down
2 changes: 2 additions & 0 deletions qiskit-superstaq/qiskit_superstaq/superstaq_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __init__(
api_version: str = gss.API_VERSION,
max_retry_seconds: int = 3600,
verbose: bool = False,
**kwargs: Any,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be added to docstring

) -> None:
"""Initializes a SuperstaqProvider.

Expand Down Expand Up @@ -83,6 +84,7 @@ def __init__(
api_version=api_version,
max_retry_seconds=max_retry_seconds,
verbose=verbose,
**kwargs,
)

def __str__(self) -> str:
Expand Down