From 8cbbfc65044bedc8ec851b9190691211c8c77ac4 Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 11:52:36 -0600 Subject: [PATCH 01/11] fix small testing bugs --- cirq-superstaq/cirq_superstaq/compiler_output_test.py | 2 +- general-superstaq/general_superstaq/superstaq_client.py | 5 ----- qiskit-superstaq/qiskit_superstaq/daily_integration_test.py | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/cirq-superstaq/cirq_superstaq/compiler_output_test.py b/cirq-superstaq/cirq_superstaq/compiler_output_test.py index 201b006ce..5a89a6a92 100644 --- a/cirq-superstaq/cirq_superstaq/compiler_output_test.py +++ b/cirq-superstaq/cirq_superstaq/compiler_output_test.py @@ -234,7 +234,7 @@ def test_read_json_ibmq_warnings() -> None: with pytest.warns( UserWarning, - match="Your compiled pulse sequences could not be deserialized. Please let us know", + match="Your compiled pulse sequences could not be deserialized", ): out = css.compiler_output.read_json(json_dict, circuits_is_list=True) assert out.circuits == [circuit] diff --git a/general-superstaq/general_superstaq/superstaq_client.py b/general-superstaq/general_superstaq/superstaq_client.py index 28b2dffb5..f0107b6ea 100644 --- a/general-superstaq/general_superstaq/superstaq_client.py +++ b/general-superstaq/general_superstaq/superstaq_client.py @@ -27,7 +27,6 @@ import requests import general_superstaq as gss -from general_superstaq.testing import TARGET_LIST class _SuperstaqClient: @@ -361,10 +360,6 @@ def submit_qubo( A dictionary from the POST request. """ gss.validation.validate_target(target) - if not (target in TARGET_LIST and TARGET_LIST[target]["supports_submit_qubo"]): - raise gss.SuperstaqException( - f"The provided target, {target}, does not support QUBO submission." - ) gss.validation.validate_integer_param(repetitions) gss.validation.validate_integer_param(max_solutions) diff --git a/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py b/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py index 30938722f..c7ad6ec61 100644 --- a/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py +++ b/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py @@ -29,7 +29,7 @@ def test_backends(provider: qss.SuperstaqProvider) -> None: retired=False, ) assert ibmq_backend_info in result - assert provider.get_backend("ibmq_qasm_simulator").name == "ibmq_qasm_simulator" + assert provider.get_backend("ibmq_qasm_simulator").name() == "ibmq_qasm_simulator" def test_ibmq_compile(provider: qss.SuperstaqProvider) -> None: From 4a384d1c9feabc5a40f7aec7e79c51457e8863f6 Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 11:55:42 -0600 Subject: [PATCH 02/11] mock version --- cirq-superstaq/cirq_superstaq/compiler_output_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cirq-superstaq/cirq_superstaq/compiler_output_test.py b/cirq-superstaq/cirq_superstaq/compiler_output_test.py index 5a89a6a92..c8a38f61f 100644 --- a/cirq-superstaq/cirq_superstaq/compiler_output_test.py +++ b/cirq-superstaq/cirq_superstaq/compiler_output_test.py @@ -232,9 +232,9 @@ def test_read_json_ibmq_warnings() -> None: assert out.circuits == [circuit] assert out.pulse_sequences is None - with pytest.warns( + with mock.patch("qiskit.__version__", "2.0.0"), pytest.warns( UserWarning, - match="Your compiled pulse sequences could not be deserialized", + match="Your compiled pulse sequences could not be deserialized. Please let us know", ): out = css.compiler_output.read_json(json_dict, circuits_is_list=True) assert out.circuits == [circuit] From dbaf358ff55d75993a09cd3d723d26e56f9353fd Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 13:40:02 -0600 Subject: [PATCH 03/11] inline qubo deserialization --- .../cirq_superstaq/daily_integration_test.py | 3 +-- general-superstaq/general_superstaq/__init__.py | 2 -- general-superstaq/general_superstaq/qubo.py | 15 --------------- general-superstaq/general_superstaq/qubo_test.py | 10 ---------- general-superstaq/general_superstaq/service.py | 5 +++-- .../qiskit_superstaq/daily_integration_test.py | 3 +-- 6 files changed, 5 insertions(+), 33 deletions(-) delete mode 100644 general-superstaq/general_superstaq/qubo.py delete mode 100644 general-superstaq/general_superstaq/qubo_test.py diff --git a/cirq-superstaq/cirq_superstaq/daily_integration_test.py b/cirq-superstaq/cirq_superstaq/daily_integration_test.py index a7ddcee89..972f986dd 100644 --- a/cirq-superstaq/cirq_superstaq/daily_integration_test.py +++ b/cirq-superstaq/cirq_superstaq/daily_integration_test.py @@ -332,9 +332,8 @@ def test_submit_qubo(service: css.Service) -> None: (0, 1): 2, (1, 2): 2, } - serialized_result = service.submit_qubo( + result = service.submit_qubo( test_qubo, target="toshiba_bifurcation_simulator", method="dry-run" ) - result = gss.qubo.read_json_qubo_result(serialized_result) best_result = result[0] assert best_result == {0: 1, 1: 0, 2: 1} diff --git a/general-superstaq/general_superstaq/__init__.py b/general-superstaq/general_superstaq/__init__.py index 20799ff66..3c280529f 100644 --- a/general-superstaq/general_superstaq/__init__.py +++ b/general-superstaq/general_superstaq/__init__.py @@ -10,7 +10,6 @@ from general_superstaq.typing import Target from . import ( - qubo, serialization, service, superstaq_client, @@ -28,7 +27,6 @@ "SuperstaqUnsuccessfulJobException", "SuperstaqServerException", "SuperstaqWarning", - "qubo", "serialization", "service", "superstaq_client", diff --git a/general-superstaq/general_superstaq/qubo.py b/general-superstaq/general_superstaq/qubo.py deleted file mode 100644 index 539ce1cb7..000000000 --- a/general-superstaq/general_superstaq/qubo.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import annotations - -import general_superstaq as gss - - -def read_json_qubo_result(json_dict: dict[str, str]) -> list[dict[tuple[int], int]]: - """Reads out returned JSON from Superstaq API's QUBO endpoint. - - Args: - json_dict: A JSON dictionary matching the format returned by the /qubo endpoint. - - Returns: - A `numpy.recarray` containing the results of the optimization. - """ - return gss.serialization.deserialize(json_dict["solution"]) diff --git a/general-superstaq/general_superstaq/qubo_test.py b/general-superstaq/general_superstaq/qubo_test.py deleted file mode 100644 index 0641bd1df..000000000 --- a/general-superstaq/general_superstaq/qubo_test.py +++ /dev/null @@ -1,10 +0,0 @@ -# pylint: disable=missing-function-docstring,missing-class-docstring -import general_superstaq as gss - - -def test_read_json_qubo_result() -> None: - deserialized_return = [{0: 0, 1: 0, 2: 0, 3: 0, 4: 0}] - - server_return = {"solution": gss.serialization.serialize(deserialized_return)} - - assert repr(gss.qubo.read_json_qubo_result(server_return)) == repr(deserialized_return) diff --git a/general-superstaq/general_superstaq/service.py b/general-superstaq/general_superstaq/service.py index 1218f3c00..19391e401 100644 --- a/general-superstaq/general_superstaq/service.py +++ b/general-superstaq/general_superstaq/service.py @@ -164,7 +164,7 @@ def submit_qubo( repetitions: int = 1000, method: str | None = None, max_solutions: int = 1000, - ) -> dict[str, str]: + ) -> list[dict[tuple[int, ...], int]]: """Solves a submitted QUBO problem via annealing. This method returns any number of specified dictionaries that seek the minimum of @@ -186,7 +186,8 @@ def submit_qubo( Returns: A dictionary containing the output solutions. """ - return self._client.submit_qubo(qubo, target, repetitions, method, max_solutions) + result_dict = self._client.submit_qubo(qubo, target, repetitions, method, max_solutions) + return gss.serialization.deserialize(result_dict["solution"]) def aqt_upload_configs(self, pulses: Any, variables: Any) -> str: """Uploads configs for AQT. diff --git a/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py b/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py index c7ad6ec61..3c644a078 100644 --- a/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py +++ b/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py @@ -288,9 +288,8 @@ def test_submit_qubo(provider: qss.SuperstaqProvider) -> None: (0, 1): 2, (1, 2): 2, } - serialized_result = provider.submit_qubo( + result = provider.submit_qubo( test_qubo, target="toshiba_bifurcation_simulator", method="dry-run" ) - result = gss.qubo.read_json_qubo_result(serialized_result) best_result = result[0] assert best_result == {0: 1, 1: 0, 2: 1} From d3d62c6a559cea6bb35eb1881a0214f77e6a2a4d Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 13:43:04 -0600 Subject: [PATCH 04/11] fix notebook --- docs/source/apps/max_sharpe_ratio_optimization.ipynb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/apps/max_sharpe_ratio_optimization.ipynb b/docs/source/apps/max_sharpe_ratio_optimization.ipynb index 6c0d7f547..fe9507c37 100644 --- a/docs/source/apps/max_sharpe_ratio_optimization.ipynb +++ b/docs/source/apps/max_sharpe_ratio_optimization.ipynb @@ -1033,8 +1033,7 @@ "from qubovert.sim import anneal_qubo\n", "\n", "res = client.submit_qubo(obj_QUBO, target=\"toshiba_bifurcation_simulator\", method=\"dry-run\")\n", - "# res = client.submit_qubo(obj_QUBO, target=\"toshiba_bifurcation_simulator\")\n", - "res = gss.qubo.read_json_qubo_result(res)" + "# res = client.submit_qubo(obj_QUBO, target=\"toshiba_bifurcation_simulator\")\n" ] }, { From 09071ddace94142230cae1f86068abca95e72669 Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 13:59:12 -0600 Subject: [PATCH 05/11] fix tests and format --- .../cirq_superstaq/compiler_output_test.py | 2 +- .../apps/max_sharpe_ratio_optimization.ipynb | 2 +- .../general_superstaq/__init__.py | 9 +----- .../general_superstaq/service.py | 2 +- .../general_superstaq/service_test.py | 29 ++++--------------- 5 files changed, 10 insertions(+), 34 deletions(-) diff --git a/cirq-superstaq/cirq_superstaq/compiler_output_test.py b/cirq-superstaq/cirq_superstaq/compiler_output_test.py index c8a38f61f..cabd0c9e4 100644 --- a/cirq-superstaq/cirq_superstaq/compiler_output_test.py +++ b/cirq-superstaq/cirq_superstaq/compiler_output_test.py @@ -232,7 +232,7 @@ def test_read_json_ibmq_warnings() -> None: assert out.circuits == [circuit] assert out.pulse_sequences is None - with mock.patch("qiskit.__version__", "2.0.0"), pytest.warns( + with mock.patch("qiskit.__version__", "2.0.0"), pytest.warns( UserWarning, match="Your compiled pulse sequences could not be deserialized. Please let us know", ): diff --git a/docs/source/apps/max_sharpe_ratio_optimization.ipynb b/docs/source/apps/max_sharpe_ratio_optimization.ipynb index fe9507c37..85422edfe 100644 --- a/docs/source/apps/max_sharpe_ratio_optimization.ipynb +++ b/docs/source/apps/max_sharpe_ratio_optimization.ipynb @@ -1033,7 +1033,7 @@ "from qubovert.sim import anneal_qubo\n", "\n", "res = client.submit_qubo(obj_QUBO, target=\"toshiba_bifurcation_simulator\", method=\"dry-run\")\n", - "# res = client.submit_qubo(obj_QUBO, target=\"toshiba_bifurcation_simulator\")\n" + "# res = client.submit_qubo(obj_QUBO, target=\"toshiba_bifurcation_simulator\")" ] }, { diff --git a/general-superstaq/general_superstaq/__init__.py b/general-superstaq/general_superstaq/__init__.py index 3c280529f..f80cfe829 100644 --- a/general-superstaq/general_superstaq/__init__.py +++ b/general-superstaq/general_superstaq/__init__.py @@ -9,14 +9,7 @@ ) from general_superstaq.typing import Target -from . import ( - serialization, - service, - superstaq_client, - superstaq_exceptions, - typing, - validation, -) +from . import serialization, service, superstaq_client, superstaq_exceptions, typing, validation __all__ = [ "__version__", diff --git a/general-superstaq/general_superstaq/service.py b/general-superstaq/general_superstaq/service.py index 19391e401..5a8b68aad 100644 --- a/general-superstaq/general_superstaq/service.py +++ b/general-superstaq/general_superstaq/service.py @@ -164,7 +164,7 @@ def submit_qubo( repetitions: int = 1000, method: str | None = None, max_solutions: int = 1000, - ) -> list[dict[tuple[int, ...], int]]: + ) -> list[dict[int, int]]: """Solves a submitted QUBO problem via annealing. This method returns any number of specified dictionaries that seek the minimum of diff --git a/general-superstaq/general_superstaq/service_test.py b/general-superstaq/general_superstaq/service_test.py index ae17ee4a4..dd944951a 100644 --- a/general-superstaq/general_superstaq/service_test.py +++ b/general-superstaq/general_superstaq/service_test.py @@ -77,22 +77,12 @@ def test_update_user_role( @mock.patch( "general_superstaq.superstaq_client._SuperstaqClient.post_request", - return_value={ - "qubo": [ - {"keys": ["0"], "value": 1.0}, - {"keys": ["1"], "value": 1.0}, - {"keys": ["0", "1"], "value": -2.0}, - ], - "target": "toshiba_bifurcation_simulator", - "shots": 10, - "method": "dry-run", - "max_solutions": 13, - }, + return_value={"solution": gss.serialization.serialize([{0: 1, 1: 1}] * 10)}, ) def test_submit_qubo( mock_post_request: mock.MagicMock, ) -> None: - example_qubo: dict[tuple[()] | tuple[str | int] | tuple[str | int, str | int], int | float] = { + example_qubo: dict[tuple[int, ...], float] = { (0,): 1.0, (1,): 1.0, (0, 1): -2.0, @@ -101,17 +91,10 @@ def test_submit_qubo( repetitions = 10 service = gss.service.Service(remote_host="http://example.com", api_key="key") - assert service.submit_qubo(example_qubo, target, repetitions=repetitions, method="dry-run") == { - "qubo": [ - {"keys": ["0"], "value": 1.0}, - {"keys": ["1"], "value": 1.0}, - {"keys": ["0", "1"], "value": -2.0}, - ], - "target": "toshiba_bifurcation_simulator", - "shots": 10, - "method": "dry-run", - "max_solutions": 13, - } + assert ( + service.submit_qubo(example_qubo, target, repetitions=repetitions, method="dry-run") + == [{0: 1, 1: 1}] * 10 + ) @mock.patch( From 38a7c96d91a88b7db67b4064f4dd4b46347a12d8 Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 14:22:18 -0600 Subject: [PATCH 06/11] fix typing --- .../cirq_superstaq/daily_integration_test.py | 2 +- general-superstaq/general_superstaq/service.py | 10 ++++++---- general-superstaq/general_superstaq/service_test.py | 2 +- .../general_superstaq/superstaq_client.py | 6 ++++-- .../general_superstaq/superstaq_client_test.py | 11 +---------- .../qiskit_superstaq/daily_integration_test.py | 2 +- 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/cirq-superstaq/cirq_superstaq/daily_integration_test.py b/cirq-superstaq/cirq_superstaq/daily_integration_test.py index 972f986dd..2dc4d02c3 100644 --- a/cirq-superstaq/cirq_superstaq/daily_integration_test.py +++ b/cirq-superstaq/cirq_superstaq/daily_integration_test.py @@ -325,7 +325,7 @@ def test_submit_to_hilbert_qubit_sorting(service: css.Service) -> None: def test_submit_qubo(service: css.Service) -> None: - test_qubo: dict[tuple[()] | tuple[str | int] | tuple[str | int, str | int], int | float] = { + test_qubo = { (0,): -1, (1,): -1, (2,): -1, diff --git a/general-superstaq/general_superstaq/service.py b/general-superstaq/general_superstaq/service.py index 5a8b68aad..d3638a0dd 100644 --- a/general-superstaq/general_superstaq/service.py +++ b/general-superstaq/general_superstaq/service.py @@ -2,11 +2,13 @@ import numbers import os -from collections.abc import Sequence -from typing import Any +from collections.abc import Mapping, Sequence +from typing import Any, TypeVar import general_superstaq as gss +TQuboKey = TypeVar("TQuboKey") + class Service: """This class contains all the services that are used to operate Superstaq.""" @@ -159,12 +161,12 @@ def get_targets( def submit_qubo( self, - qubo: dict[tuple[()] | tuple[str | int] | tuple[str | int, str | int], int | float], + qubo: Mapping[tuple[TQuboKey, ...], float], target: str, repetitions: int = 1000, method: str | None = None, max_solutions: int = 1000, - ) -> list[dict[int, int]]: + ) -> list[dict[TQuboKey, int]]: """Solves a submitted QUBO problem via annealing. This method returns any number of specified dictionaries that seek the minimum of diff --git a/general-superstaq/general_superstaq/service_test.py b/general-superstaq/general_superstaq/service_test.py index dd944951a..21d82f6f7 100644 --- a/general-superstaq/general_superstaq/service_test.py +++ b/general-superstaq/general_superstaq/service_test.py @@ -82,7 +82,7 @@ def test_update_user_role( def test_submit_qubo( mock_post_request: mock.MagicMock, ) -> None: - example_qubo: dict[tuple[int, ...], float] = { + example_qubo = { (0,): 1.0, (1,): 1.0, (0, 1): -2.0, diff --git a/general-superstaq/general_superstaq/superstaq_client.py b/general-superstaq/general_superstaq/superstaq_client.py index f0107b6ea..e7cf9d777 100644 --- a/general-superstaq/general_superstaq/superstaq_client.py +++ b/general-superstaq/general_superstaq/superstaq_client.py @@ -22,12 +22,14 @@ import urllib import warnings from collections.abc import Callable, Mapping, Sequence -from typing import Any +from typing import Any, TypeVar import requests import general_superstaq as gss +TQuboKey = TypeVar("TQuboKey") + class _SuperstaqClient: """Handles calls to Superstaq's API. @@ -334,7 +336,7 @@ def compile(self, json_dict: dict[str, str]) -> dict[str, str]: def submit_qubo( self, - qubo: dict[tuple[()] | tuple[str | int] | tuple[str | int, str | int], int | float], + qubo: Mapping[tuple[TQuboKey, ...], float], target: str, repetitions: int = 1000, method: str | None = None, diff --git a/general-superstaq/general_superstaq/superstaq_client_test.py b/general-superstaq/general_superstaq/superstaq_client_test.py index fc6bea484..b165fd585 100644 --- a/general-superstaq/general_superstaq/superstaq_client_test.py +++ b/general-superstaq/general_superstaq/superstaq_client_test.py @@ -646,7 +646,7 @@ def test_superstaq_client_submit_qubo(mock_post: mock.MagicMock) -> None: api_key="to_my_heart", ) - example_qubo: dict[tuple[()] | tuple[str | int] | tuple[str | int, str | int], int | float] = { + example_qubo = { ("a",): 2.0, ("a", "b"): 1.0, ("b", 0): -5, @@ -673,15 +673,6 @@ def test_superstaq_client_submit_qubo(mock_post: mock.MagicMock) -> None: verify=False, ) - with pytest.raises(gss.SuperstaqException, match="not support QUBO submission."): - client.submit_qubo( - example_qubo, - target="cq_hilbert_qpu", - repetitions=repetitions, - method="dry-run", - max_solutions=1, - ) - @mock.patch("requests.post") def test_superstaq_client_supercheq(mock_post: mock.MagicMock) -> None: diff --git a/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py b/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py index 3c644a078..caab738ee 100644 --- a/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py +++ b/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py @@ -281,7 +281,7 @@ def test_submit_to_hilbert_qubit_sorting(provider: qss.SuperstaqProvider) -> Non def test_submit_qubo(provider: qss.SuperstaqProvider) -> None: - test_qubo: dict[tuple[()] | tuple[str | int] | tuple[str | int, str | int], int | float] = { + test_qubo = { (0,): -1, (1,): -1, (2,): -1, From 8d011ec57ee256b1cb8f69d6c23d0c3db6993c75 Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 15:04:18 -0600 Subject: [PATCH 07/11] drop default --- general-superstaq/general_superstaq/superstaq_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/general-superstaq/general_superstaq/superstaq_client.py b/general-superstaq/general_superstaq/superstaq_client.py index e7cf9d777..456da822e 100644 --- a/general-superstaq/general_superstaq/superstaq_client.py +++ b/general-superstaq/general_superstaq/superstaq_client.py @@ -338,7 +338,7 @@ def submit_qubo( self, qubo: Mapping[tuple[TQuboKey, ...], float], target: str, - repetitions: int = 1000, + repetitions: int, method: str | None = None, max_solutions: int | None = 1000, ) -> dict[str, str]: From e91baa8a74827966ec41d1d358d1a300c3606138 Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 16:12:41 -0600 Subject: [PATCH 08/11] input validation --- .../general_superstaq/superstaq_client.py | 1 + .../general_superstaq/validation.py | 26 ++++++++++++++++++- .../general_superstaq/validation_test.py | 21 +++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/general-superstaq/general_superstaq/superstaq_client.py b/general-superstaq/general_superstaq/superstaq_client.py index 456da822e..824cc06d8 100644 --- a/general-superstaq/general_superstaq/superstaq_client.py +++ b/general-superstaq/general_superstaq/superstaq_client.py @@ -362,6 +362,7 @@ def submit_qubo( A dictionary from the POST request. """ gss.validation.validate_target(target) + gss.validation.validate_qubo(qubo) gss.validation.validate_integer_param(repetitions) gss.validation.validate_integer_param(max_solutions) diff --git a/general-superstaq/general_superstaq/validation.py b/general-superstaq/general_superstaq/validation.py index d438efdc7..df74b5e73 100644 --- a/general-superstaq/general_superstaq/validation.py +++ b/general-superstaq/general_superstaq/validation.py @@ -1,7 +1,8 @@ from __future__ import annotations +import numbers import re -from collections.abc import Sequence +from collections.abc import Mapping, Sequence def validate_integer_param(integer_param: object, min_val: int = 1) -> None: @@ -136,3 +137,26 @@ def validate_noise_type(noise: dict[str, object], n_qubits: int) -> None: f"{params} must be of the form (p_x, p_y, p_z) such that p_x + p_y + p_z <= 1 " f'for "asymmetric_depolarize".' ) + + +def validate_qubo(qubo: object) -> None: + """Validates that the input can be converted into a valid QUBO. + + Args: + qubo: The input value to validate. + + Raises: + ValueError: If the provided object cannot be converted into a valid QUBO. + """ + if not isinstance(qubo, Mapping): + raise ValueError("QUBOs must be provided as dict-like objects.") + + for key, val in qubo.items(): + if not isinstance(key, Sequence) or isinstance(key, str): + raise ValueError(f"{key!r} is not a valid key for a QUBO.") + + if len(key) > 2: + raise ValueError(f"QUBOs must be quadratic, but key {key!r} has length {len(key)}.") + + if not isinstance(val, numbers.Real): + raise ValueError("QUBO values must be real numbers.") diff --git a/general-superstaq/general_superstaq/validation_test.py b/general-superstaq/general_superstaq/validation_test.py index a752bf909..32a6e0258 100644 --- a/general-superstaq/general_superstaq/validation_test.py +++ b/general-superstaq/general_superstaq/validation_test.py @@ -74,3 +74,24 @@ def test_validate_noise_type() -> None: gss.validation.validate_noise_type( ({"type": "asymmetric_depolarize", "params": (0.5, 0.5, 0.5)}), 1 ) + + +def test_validate_qubo() -> None: + with pytest.raises(ValueError, match="QUBOs must be"): + gss.validation.validate_qubo("not-a-dict") + + with pytest.raises(ValueError, match="not a valid key"): + gss.validation.validate_qubo({"abc": 123}) + + with pytest.raises(ValueError, match="must be real numbers"): + gss.validation.validate_qubo({(1, 2): 12 + 3j}) + + with pytest.raises(ValueError, match="must be real numbers"): + gss.validation.validate_qubo({(1, 2): "abc"}) + + with pytest.raises(ValueError, match="must be quadratic"): + gss.validation.validate_qubo({(1, 2, 3): 123}) + + gss.validation.validate_qubo({(1,): 1.2, (2,): 2.3, (1, 2): -3.4}) + gss.validation.validate_qubo({("a",): 1, ("b",): 2, ("a", "b"): -3}) + gss.validation.validate_qubo({(): 123}) From e61c4b11e6855fc9cfa70085fd1fe1c3f8f40ae8 Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 16:49:05 -0600 Subject: [PATCH 09/11] typo --- cirq-superstaq/cirq_superstaq/daily_integration_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-superstaq/cirq_superstaq/daily_integration_test.py b/cirq-superstaq/cirq_superstaq/daily_integration_test.py index 05b284129..b1cd69631 100644 --- a/cirq-superstaq/cirq_superstaq/daily_integration_test.py +++ b/cirq-superstaq/cirq_superstaq/daily_integration_test.py @@ -332,7 +332,7 @@ def test_submit_qubo(service: css.Service) -> None: (0, 1): 2, (1, 2): 2, } - result_result = service.submit_qubo( + result = service.submit_qubo( test_qubo, target="ss_unconstrained_simulator", repetitions=10 ) assert len(result) == 10 From ca63ffbf1016c2959c6697b62ab9b2c895afdecd Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 16:50:50 -0600 Subject: [PATCH 10/11] format --- cirq-superstaq/cirq_superstaq/daily_integration_test.py | 4 +--- qiskit-superstaq/qiskit_superstaq/daily_integration_test.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cirq-superstaq/cirq_superstaq/daily_integration_test.py b/cirq-superstaq/cirq_superstaq/daily_integration_test.py index b1cd69631..8794ecc7c 100644 --- a/cirq-superstaq/cirq_superstaq/daily_integration_test.py +++ b/cirq-superstaq/cirq_superstaq/daily_integration_test.py @@ -332,8 +332,6 @@ def test_submit_qubo(service: css.Service) -> None: (0, 1): 2, (1, 2): 2, } - result = service.submit_qubo( - test_qubo, target="ss_unconstrained_simulator", repetitions=10 - ) + result = service.submit_qubo(test_qubo, target="ss_unconstrained_simulator", repetitions=10) assert len(result) == 10 assert {0: 1, 1: 0, 2: 1} in result diff --git a/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py b/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py index d5d493743..ff0e53e89 100644 --- a/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py +++ b/qiskit-superstaq/qiskit_superstaq/daily_integration_test.py @@ -288,8 +288,6 @@ def test_submit_qubo(provider: qss.SuperstaqProvider) -> None: (0, 1): 2, (1, 2): 2, } - result = provider.submit_qubo( - test_qubo, target="ss_unconstrained_simulator", repetitions=10 - ) + result = provider.submit_qubo(test_qubo, target="ss_unconstrained_simulator", repetitions=10) assert len(result) == 10 assert {0: 1, 1: 0, 2: 1} in result From 8086d3c7d08f14cbc462902f38a7d0a7d4eb37a1 Mon Sep 17 00:00:00 2001 From: rich Date: Thu, 7 Mar 2024 16:52:07 -0600 Subject: [PATCH 11/11] fix mock --- general-superstaq/general_superstaq/service_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/general-superstaq/general_superstaq/service_test.py b/general-superstaq/general_superstaq/service_test.py index d0100e8c6..96848fe46 100644 --- a/general-superstaq/general_superstaq/service_test.py +++ b/general-superstaq/general_superstaq/service_test.py @@ -76,7 +76,7 @@ def test_update_user_role( @mock.patch( - "requests.post", + "general_superstaq.superstaq_client._SuperstaqClient.post_request", return_value={"solution": gss.serialization.serialize([{0: 1, 1: 1}] * 10)}, ) def test_submit_qubo(