quantuminspire 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
File without changes
@@ -0,0 +1,202 @@
1
+ """Module containing the commands for the Quantum Inspire CLI."""
2
+
3
+ import asyncio
4
+ import webbrowser
5
+ from pathlib import Path
6
+ from typing import Optional
7
+
8
+ import typer
9
+ from compute_api_client import JobStatus
10
+ from rich import print
11
+ from rich.console import Console
12
+ from rich.table import Table
13
+ from typer import Typer
14
+
15
+ from quantuminspire.sdk.models.cqasm_algorithm import CqasmAlgorithm
16
+ from quantuminspire.sdk.models.file_algorithm import FileAlgorithm
17
+ from quantuminspire.sdk.models.hybrid_algorithm import HybridAlgorithm
18
+ from quantuminspire.sdk.models.job_options import JobOptions
19
+ from quantuminspire.util.api.local_backend import LocalBackend
20
+ from quantuminspire.util.api.remote_backend import RemoteBackend
21
+ from quantuminspire.util.authentication import OauthDeviceSession
22
+ from quantuminspire.util.configuration import Settings, Url
23
+
24
+ app = Typer(add_completion=False, no_args_is_help=True)
25
+ backend_types_app = Typer(no_args_is_help=True)
26
+ app.add_typer(backend_types_app, name="backends", help="Manage backends")
27
+ files_app = Typer(no_args_is_help=True)
28
+ app.add_typer(files_app, name="files", help="Manage files")
29
+ results_app = Typer(no_args_is_help=True)
30
+ app.add_typer(results_app, name="results", help="Manage results")
31
+ final_results_app = Typer(no_args_is_help=True)
32
+ app.add_typer(final_results_app, name="final_results", help="Manage final results")
33
+
34
+ console = Console()
35
+
36
+
37
+ @backend_types_app.command("list")
38
+ def list_backend_types() -> None:
39
+ """List backends.
40
+
41
+ List all available backends and their configuration.
42
+ """
43
+ backend = RemoteBackend()
44
+ backend_types = backend.get_backend_types().items
45
+ table = Table("id", "name", "status", "is_hardware", "supports_raw_data", "number_of_qubits", "max_number_of_shots")
46
+ for backend_type in backend_types:
47
+ table.add_row(
48
+ str(backend_type.id),
49
+ backend_type.name,
50
+ str(backend_type.status.name),
51
+ str(backend_type.is_hardware),
52
+ str(backend_type.supports_raw_data),
53
+ str(backend_type.nqubits),
54
+ str(backend_type.max_number_of_shots),
55
+ )
56
+ console.print(table)
57
+
58
+
59
+ def load_algorithm_from_file(file_path: Path) -> FileAlgorithm:
60
+ """Load an algorithm from a file."""
61
+ if file_path.suffix == ".py":
62
+ algorithm: FileAlgorithm = HybridAlgorithm("", str(file_path))
63
+ elif file_path.suffix == ".cq":
64
+ algorithm = CqasmAlgorithm("", str(file_path))
65
+ else:
66
+ raise ValueError(f"Unsupported file type: {file_path.suffix}. Supported types are .py and .cq")
67
+
68
+ algorithm.read_file(file_path)
69
+ return algorithm
70
+
71
+
72
+ @files_app.command("upload")
73
+ def upload_files(
74
+ name: str = typer.Argument(..., help="The name of the file to upload"),
75
+ backend_type_id: int = typer.Argument(
76
+ ..., help="The id of the backend type on which this algorithm should be executed"
77
+ ),
78
+ num_shots: int = typer.Option(
79
+ 1024, help="The number of shots to run the algorithm (only for pure cQASM algorithms)"
80
+ ),
81
+ store_raw_data: bool = typer.Option(
82
+ False, help="Whether to enable shot memory for the algorithm (only for pure cQASM algorithms)"
83
+ ),
84
+ ) -> None:
85
+ """Upload a file to the QI API.
86
+
87
+ Upload a file containing either a Hybrid (.py) or a Quantum (.cq) algorithm, and run it on the QI platform.
88
+ """
89
+ backend = RemoteBackend()
90
+ program = load_algorithm_from_file(Path(name))
91
+ program.read_file(Path(name))
92
+ job_options = JobOptions(number_of_shots=num_shots, raw_data_enabled=store_raw_data)
93
+ job_id = backend.run(program, backend_type_id=backend_type_id, options=job_options)
94
+ typer.echo(f"Upload file with name: {name}")
95
+ typer.echo(f"job_id {job_id}")
96
+
97
+
98
+ @files_app.command("run")
99
+ def run_file(
100
+ name: str = typer.Argument(..., help="The full path of the file to run"),
101
+ ) -> None:
102
+ """Run a file locally.
103
+
104
+ Run a Hybrid Quantum/Classical Algorithm locally. The quantum part will be run with QXEmulator.
105
+ """
106
+ algorithm = HybridAlgorithm("test", "test")
107
+ algorithm.read_file(Path(name))
108
+
109
+ local_backend = LocalBackend()
110
+ job_id = local_backend.run(algorithm, 0)
111
+ results = local_backend.get_results(job_id)
112
+ typer.echo(f"{results}")
113
+
114
+
115
+ def _has_job_failed(backend: RemoteBackend, job_id: int) -> None:
116
+ """Check if a job has failed and exit with error_code 1 if it has."""
117
+ job = backend.get_job(job_id)
118
+ if job.status == JobStatus.FAILED:
119
+ job.message = job.message or "Job failed."
120
+ typer.echo(job.message, err=True)
121
+ typer.echo(f"Trace id: {job.trace_id}", err=True)
122
+ raise typer.Exit(1)
123
+
124
+
125
+ @results_app.command("get")
126
+ def get_results(job_id: int = typer.Argument(..., help="The id of the run")) -> None:
127
+ """Retrieve the results for a run.
128
+
129
+ Takes the id as returned by upload_files and retrieves the results for that run, if it's finished.
130
+ """
131
+ backend = RemoteBackend()
132
+ _has_job_failed(backend, job_id)
133
+ results = backend.get_results(job_id)
134
+
135
+ if results is None:
136
+ typer.echo("No results.")
137
+ raise typer.Exit(1)
138
+
139
+ typer.echo("Raw results:")
140
+ print(results.model_dump())
141
+
142
+
143
+ @final_results_app.command("get")
144
+ def get_final_results(job_id: int = typer.Argument(..., help="The id of the run")) -> None:
145
+ """Retrieve the final results for a run.
146
+
147
+ Takes the id as returned by upload_files and retrieves the final results for that job, if it's finished.
148
+ """
149
+ backend = RemoteBackend()
150
+ _has_job_failed(backend, job_id)
151
+ results = backend.get_final_results(job_id)
152
+
153
+ if results is None:
154
+ typer.echo("No final results.")
155
+ raise typer.Exit(1)
156
+
157
+ typer.echo("Raw final results:")
158
+ print(results.model_dump())
159
+
160
+
161
+ @app.command("login")
162
+ def login(
163
+ host: Optional[str] = typer.Argument(None, help="The URL of the platform to which to connect"),
164
+ override_auth_config: bool = typer.Option(
165
+ False,
166
+ help="Will ignore authentication configuration suggested by the API and use stored configuration instead",
167
+ ),
168
+ ) -> None:
169
+ """Log in to Quantum Inspire.
170
+
171
+ Log in to the Quantum Inspire platform. The host can be overwritten, so that the user can connect to different
172
+ instances. If no host is specified, the production environment will be used.
173
+ """
174
+ settings = Settings()
175
+ host = host or settings.default_host
176
+ host_url = Url(host)
177
+ settings.default_host = host_url
178
+
179
+ if not override_auth_config:
180
+ asyncio.run(settings.fetch_auth_settings(host_url))
181
+
182
+ auth_session = OauthDeviceSession(settings.auths[host_url])
183
+
184
+ login_info = auth_session.initialize_authorization()
185
+ typer.echo(f"Please continue logging in by opening: {login_info['verification_uri_complete']} in your browser")
186
+ typer.echo(f"If promped to verify a code, please confirm it is as follows: {login_info['user_code']}")
187
+ webbrowser.open(login_info["verification_uri_complete"], new=2)
188
+ tokens = auth_session.poll_for_tokens()
189
+ settings.store_tokens(host_url, tokens)
190
+ typer.echo("Login successful!")
191
+ typer.echo(f"Using member ID {settings.auths[host].team_member_id}")
192
+
193
+
194
+ @app.command("set-default-host")
195
+ def set_default_host(
196
+ host: str = typer.Argument(help="The URL of the platform to which to connect"),
197
+ ) -> None:
198
+ """Set default_host for interacting with Quantum Inspire."""
199
+ settings = Settings()
200
+ settings.default_host = Url(host)
201
+ settings.write_settings_to_file()
202
+ typer.echo(f"Default host set to {host}")
File without changes
File without changes
File without changes
@@ -0,0 +1,64 @@
1
+ """Module containing the Abstract Base Class for Algorithm classes."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+
6
+ class BaseAlgorithm(ABC):
7
+ """A container object, used to store content and metadata for the algorithm."""
8
+
9
+ def __init__(self, platform_name: str, program_name: str) -> None:
10
+ self._platform_name = platform_name
11
+ self._program_name = program_name
12
+
13
+ @property
14
+ def program_name(self) -> str:
15
+ """Return the name of the program.
16
+
17
+ Returns:
18
+ The string representation of the program name.
19
+ """
20
+ return self._program_name
21
+
22
+ @property
23
+ def platform_name(self) -> str:
24
+ """Return the name of the platform the algorithm is intended to run on.
25
+
26
+ Returns:
27
+ The string representation of the platform name.
28
+ """
29
+ return self._platform_name
30
+
31
+ @property
32
+ @abstractmethod
33
+ def content(self) -> str:
34
+ """Return the content.
35
+
36
+ Returns:
37
+ The string representation of the program.
38
+ """
39
+
40
+ @property
41
+ @abstractmethod
42
+ def content_type(self) -> str:
43
+ """Return the content type.
44
+
45
+ Returns:
46
+ The string representation of the `AlgorithmType`.
47
+ """
48
+
49
+ @property
50
+ @abstractmethod
51
+ def compile_stage(self) -> str:
52
+ """Return the compile stage.
53
+
54
+ Returns:
55
+ The string representation of the `CompileStage`.
56
+ """
57
+
58
+ @property
59
+ @abstractmethod
60
+ def language_name(self) -> str:
61
+ """The name of the language the algorithm in the file is written in.
62
+
63
+ Should match a language in the API.
64
+ """
@@ -0,0 +1,79 @@
1
+ """Module containing the Quantum Circuit class."""
2
+
3
+ from types import TracebackType
4
+ from typing import Optional, Type
5
+
6
+ from compute_api_client import AlgorithmType, CompileStage
7
+ from opensquirrel import CircuitBuilder
8
+
9
+ from quantuminspire.sdk.models.base_algorithm import BaseAlgorithm
10
+
11
+
12
+ class Circuit(BaseAlgorithm):
13
+ """A container object, interacting with OpenSquirrel and storing cQASM internally.
14
+
15
+ A circuit wraps OpenSquirrel to handle the boilerplate code for the CircuitBuilder.
16
+ """
17
+
18
+ def __init__(
19
+ self, platform_name: str, program_name: str, number_of_qubits: int, bit_registers: Optional[int] = None
20
+ ) -> None:
21
+ super().__init__(platform_name, program_name)
22
+ self._number_of_qubits = number_of_qubits
23
+ if bit_registers is None:
24
+ bit_registers = number_of_qubits
25
+ self._number_of_bit_registers = bit_registers
26
+ self.ir = CircuitBuilder(qubit_register_size=number_of_qubits, bit_register_size=bit_registers)
27
+ self._cqasm: str = ""
28
+
29
+ @property
30
+ def content(self) -> str:
31
+ return self._cqasm
32
+
33
+ @property
34
+ def content_type(self) -> AlgorithmType:
35
+ return AlgorithmType.QUANTUM
36
+
37
+ @property
38
+ def compile_stage(self) -> CompileStage:
39
+ return CompileStage.NONE
40
+
41
+ def __enter__(self) -> "Circuit":
42
+ self.initialize()
43
+ return self
44
+
45
+ def __exit__(
46
+ self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
47
+ ) -> bool:
48
+ self.finalize()
49
+ return exc_type is None
50
+
51
+ @property
52
+ def language_name(self) -> str:
53
+ return "cQASM"
54
+
55
+ def initialize(self) -> None:
56
+ """Initialize the quantum circuit."""
57
+
58
+ def finalize(self) -> None:
59
+ """Finalize the quantum circuit.
60
+
61
+ After finishing writing the quantum circuit various actions are performed to generate the actual cQASM circuit.
62
+ The circuit is converted to cQASM. Due to some differences between OpenSquirrel and QX, the casing of the gates
63
+ need to be tweaked.
64
+ """
65
+ self._cqasm = str(self.ir.to_circuit())
66
+ self._cqasm = (
67
+ self._cqasm.replace("h", "H")
68
+ .replace("cnot", "CNOT")
69
+ .replace("x", "X")
70
+ .replace("y", "Y")
71
+ .replace("z", "Z")
72
+ .replace("x90", "X90")
73
+ .replace("mx90", "mX90")
74
+ .replace("y90", "Y90")
75
+ .replace("my90", "mY90")
76
+ .replace("RZ", "Rz")
77
+ .replace("RX", "Rx")
78
+ .replace("cz", "CZ")
79
+ )
@@ -0,0 +1,20 @@
1
+ """Module containing the Quantum Algorithm class."""
2
+
3
+ from compute_api_client import AlgorithmType
4
+
5
+ from quantuminspire.sdk.models.file_algorithm import FileAlgorithm
6
+
7
+
8
+ class CqasmAlgorithm(FileAlgorithm):
9
+ """A container object, reading the python algorithm and keeping metadata.
10
+
11
+ The CqasmAlgorithm reads the python file describing the algorithm and stores it in `.content`.
12
+ """
13
+
14
+ @property
15
+ def content_type(self) -> AlgorithmType:
16
+ return AlgorithmType.QUANTUM
17
+
18
+ @property
19
+ def language_name(self) -> str:
20
+ return "cQASM"
@@ -0,0 +1,34 @@
1
+ """Module containing the Hybrid Quantum/Classical Algorithm class."""
2
+
3
+ from pathlib import Path
4
+
5
+ from compute_api_client import CompileStage
6
+
7
+ from quantuminspire.sdk.models.base_algorithm import BaseAlgorithm
8
+
9
+
10
+ class FileAlgorithm(BaseAlgorithm):
11
+ """A container object, reading the python algorithm and keeping metadata.
12
+
13
+ The FileAlgorithm reads the python file describing the algorithm and stores it in `.content`.
14
+ """
15
+
16
+ def __init__(self, platform_name: str, program_name: str) -> None:
17
+ super().__init__(platform_name, program_name)
18
+ self._content = ""
19
+
20
+ @property
21
+ def content(self) -> str:
22
+ return self._content
23
+
24
+ @property
25
+ def compile_stage(self) -> CompileStage:
26
+ return CompileStage.NONE
27
+
28
+ def read_file(self, file_pointer: Path) -> None:
29
+ """Read the python file to the wrapper.
30
+
31
+ Args:
32
+ file_pointer: the file path to the file to read.
33
+ """
34
+ self._content = file_pointer.read_text()
@@ -0,0 +1,20 @@
1
+ """Module containing the Hybrid Quantum/Classical Algorithm class."""
2
+
3
+ from compute_api_client import AlgorithmType
4
+
5
+ from quantuminspire.sdk.models.file_algorithm import FileAlgorithm
6
+
7
+
8
+ class HybridAlgorithm(FileAlgorithm):
9
+ """A container object, reading the python algorithm and keeping metadata.
10
+
11
+ The HybridAlgorithm reads the python file describing the algorithm and stores it in `.content`.
12
+ """
13
+
14
+ @property
15
+ def content_type(self) -> AlgorithmType:
16
+ return AlgorithmType.HYBRID
17
+
18
+ @property
19
+ def language_name(self) -> str:
20
+ return "Python"
@@ -0,0 +1,15 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class JobOptions(BaseModel):
5
+ """Options for running a job.
6
+
7
+ Subset of fields in the JobIn schema.
8
+ """
9
+
10
+ number_of_shots: int = Field(
11
+ 1024, ge=1, description="Number of shots for the job (only pure cQASM algorithms supported)."
12
+ )
13
+ raw_data_enabled: bool = Field(
14
+ False, description="Whether to enable shot memory for the job (only pure cQASM algorithms supported)."
15
+ )
@@ -0,0 +1,37 @@
1
+ """Quantum Inspire SDK.
2
+
3
+ Copyright 2022 QuTech Delft
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
6
+ License. You may obtain a copy of the License at
7
+
8
+ https://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
11
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
12
+ language governing permissions and limitations under the License.
13
+ """
14
+
15
+ from typing import TYPE_CHECKING, Any, List
16
+
17
+ from quantuminspire.util.api.quantum_interface import ExecuteCircuitResult, QuantumInterface as QuantumInterfaceProtocol
18
+
19
+ if TYPE_CHECKING: # pragma: no cover
20
+ from quantuminspire.util.api.local_backend import LocalBackend
21
+
22
+
23
+ class QuantumInterface(QuantumInterfaceProtocol):
24
+ """Quantum Interface implementation for running quantum circuits from hybrid algorithms."""
25
+
26
+ # pylint: disable = R0903
27
+ # R0903: Too few public methods (1/2) (too-few-public-methods)
28
+
29
+ def __init__(self, backend: "LocalBackend"):
30
+ self.backend = backend
31
+ self.results: List[Any] = []
32
+
33
+ def execute_circuit(self, circuit: str, number_of_shots: int) -> ExecuteCircuitResult:
34
+ """Execute a quantum circuit."""
35
+ results = self.backend.run_quantum(circuit, number_of_shots)
36
+ self.results.append(results.results)
37
+ return results
File without changes
File without changes
@@ -0,0 +1,35 @@
1
+ """Quantum Inspire SDK.
2
+
3
+ Copyright 2022 QuTech Delft
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
6
+ License. You may obtain a copy of the License at
7
+
8
+ https://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
11
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
12
+ language governing permissions and limitations under the License.
13
+ """
14
+
15
+ from abc import ABC, abstractmethod
16
+ from typing import Any
17
+
18
+ from quantuminspire.sdk.models.base_algorithm import BaseAlgorithm
19
+
20
+
21
+ class BaseBackend(ABC):
22
+ """Base interface for backends.
23
+
24
+ A backend will execute the hybrid algorithm, or quantum circuit provided.
25
+ """
26
+
27
+ @abstractmethod
28
+ def run(self, program: BaseAlgorithm, backend_type_id: int) -> int:
29
+ """Execute provided algorithm/circuit."""
30
+ raise NotImplementedError
31
+
32
+ @abstractmethod
33
+ def get_results(self, job_id: int) -> Any:
34
+ """Get results for algorithm/circuit."""
35
+ raise NotImplementedError
@@ -0,0 +1,110 @@
1
+ """Quantum Inspire SDK.
2
+
3
+ Copyright 2022 QuTech Delft
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
6
+ License. You may obtain a copy of the License at
7
+
8
+ https://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
11
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
12
+ language governing permissions and limitations under the License.
13
+ """
14
+
15
+ import importlib
16
+ import sys
17
+ import types
18
+ from enum import IntEnum
19
+ from typing import Any, Union
20
+
21
+ from quantuminspire.sdk.models.base_algorithm import BaseAlgorithm
22
+ from quantuminspire.sdk.models.circuit import Circuit
23
+ from quantuminspire.sdk.models.hybrid_algorithm import HybridAlgorithm
24
+ from quantuminspire.sdk.quantum_interface import QuantumInterface
25
+ from quantuminspire.util.api.base_backend import BaseBackend
26
+ from quantuminspire.util.api.quantum_interface import ExecuteCircuitResult, QuantumInterface as QuantumInterfaceProtocol
27
+
28
+
29
+ def import_qxelarator() -> types.ModuleType: # pragma: no cover
30
+ """Helper function for importing optional dependency qxelarator."""
31
+
32
+ try:
33
+ return importlib.import_module("qxelarator")
34
+ except ModuleNotFoundError as exc:
35
+ print(
36
+ "Error: Dependencies for local execution not installed, install with 'pip install quantuminspire[local]'",
37
+ file=sys.stderr,
38
+ )
39
+ raise SystemExit from exc
40
+
41
+
42
+ class LocalBackend(BaseBackend):
43
+ """Connection to remote backend.
44
+
45
+ Create a connection with the remote backend for Quantum Inspire. This connection creates the appropriate projects,
46
+ algorithms, files etc. The algorithm/circuit will also be run.
47
+ """
48
+
49
+ class JobFakeID(IntEnum):
50
+ """Helper to conform to BaseBackend interface of returning job IDs."""
51
+
52
+ QUANTUM = -1
53
+ HYBRID = -2
54
+
55
+ def __init__(self, qxelarator: Union[types.ModuleType, None] = None) -> None:
56
+ super().__init__()
57
+ self._quantum_results: Union[ExecuteCircuitResult, None] = None
58
+ self._hybrid_results: Union[Any, None] = None
59
+ self._qxelarator = qxelarator if qxelarator else import_qxelarator()
60
+
61
+ def run(self, program: BaseAlgorithm, backend_type_id: int) -> int:
62
+ """Execute provided algorithm/circuit."""
63
+ if isinstance(program, HybridAlgorithm):
64
+ quantum_interface = QuantumInterface(self)
65
+ self._hybrid_results = self.run_hybrid(program, quantum_interface)
66
+ return self.JobFakeID.HYBRID
67
+ if isinstance(program, Circuit):
68
+ self._quantum_results = self.run_quantum(program.content)
69
+ return self.JobFakeID.QUANTUM
70
+ raise AssertionError("Unknown algorithm type")
71
+
72
+ def run_hybrid(self, algorithm: HybridAlgorithm, quantum_interface: QuantumInterfaceProtocol) -> Any:
73
+ """Execute provided algorithm."""
74
+
75
+ # pylint: disable = E1101, W0122
76
+ # E1101: Instance of 'module' has no 'execute' member (no-member)
77
+ # W0122: Use of exec (exec-used)
78
+
79
+ program = types.ModuleType("mod")
80
+
81
+ exec(algorithm.content, program.__dict__)
82
+
83
+ if not hasattr(program, "execute") or not callable(program.execute):
84
+ raise AssertionError("'execute' hook not found or not callable.")
85
+ program.execute(quantum_interface)
86
+
87
+ if not hasattr(program, "finalize") or not callable(program.finalize):
88
+ raise AssertionError("'finalize' hook not found or not callable.")
89
+ result = program.finalize(quantum_interface.results)
90
+ if not isinstance(result, dict):
91
+ raise AssertionError("'finalize' hook returned invalid type, must be dict.")
92
+ return result
93
+
94
+ def run_quantum(self, circuit: str, number_of_shots: int = 1) -> ExecuteCircuitResult:
95
+ """Execute provided circuit."""
96
+ result = self._qxelarator.execute_string(circuit, iterations=number_of_shots)
97
+ return ExecuteCircuitResult(
98
+ results=result.results,
99
+ shots_done=result.shots_done,
100
+ shots_requested=result.shots_requested,
101
+ )
102
+
103
+ def get_results(self, job_id: int) -> Any:
104
+ """Get results for algorithm/circuit."""
105
+ if job_id == self.JobFakeID.QUANTUM:
106
+ return self._quantum_results
107
+ if job_id == self.JobFakeID.HYBRID:
108
+ return self._hybrid_results
109
+
110
+ raise AssertionError("Unknown job id")
@@ -0,0 +1,40 @@
1
+ """Quantum Inspire SDK.
2
+
3
+ Copyright 2022 QuTech Delft
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
6
+ License. You may obtain a copy of the License at
7
+
8
+ https://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
11
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
12
+ language governing permissions and limitations under the License.
13
+ """
14
+
15
+ from abc import ABC, abstractmethod
16
+ from typing import Any, Dict, List
17
+
18
+ from pydantic import BaseModel
19
+
20
+
21
+ class ExecuteCircuitResult(BaseModel):
22
+ """Result of executing a quantum circuit."""
23
+
24
+ results: Dict[str, float]
25
+ shots_requested: int
26
+ shots_done: int
27
+
28
+
29
+ class QuantumInterface(ABC):
30
+ """Interface for running quantum circuits from hybrid algorithms."""
31
+
32
+ # pylint: disable = R0903
33
+ # Too few public methods (1/2) (too-few-public-methods)
34
+
35
+ results: List[Any]
36
+
37
+ @abstractmethod
38
+ def execute_circuit(self, circuit: str, number_of_shots: int) -> ExecuteCircuitResult:
39
+ """Execute a quantum circuit."""
40
+ raise NotImplementedError