parityos 0.0.6__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.

Potentially problematic release.


This version of parityos might be problematic. Click here for more details.

Files changed (146) hide show
  1. parityos/__init__.py +15 -0
  2. parityos/api_interface/__init__.py +0 -0
  3. parityos/api_interface/authentication.py +87 -0
  4. parityos/api_interface/compiler_run.py +113 -0
  5. parityos/api_interface/connection.py +139 -0
  6. parityos/api_interface/exceptions.py +36 -0
  7. parityos/base/__init__.py +48 -0
  8. parityos/base/circuit.py +219 -0
  9. parityos/base/constraints.py +123 -0
  10. parityos/base/exceptions.py +20 -0
  11. parityos/base/gates.py +704 -0
  12. parityos/base/problem_representation.py +322 -0
  13. parityos/base/qubits.py +83 -0
  14. parityos/base/utils.py +124 -0
  15. parityos/compiler_client.py +146 -0
  16. parityos/device_model.py +181 -0
  17. parityos/encodings/__init__.py +0 -0
  18. parityos/encodings/mappings.py +110 -0
  19. parityos/encodings/parity_decoder.py +268 -0
  20. parityos/encodings/parity_encoder.py +39 -0
  21. parityos/encodings/parityos_output.py +248 -0
  22. parityos-0.0.6.dist-info/License.txt +37 -0
  23. parityos-0.0.6.dist-info/METADATA +34 -0
  24. parityos-0.0.6.dist-info/RECORD +146 -0
  25. parityos-0.0.6.dist-info/WHEEL +5 -0
  26. parityos-0.0.6.dist-info/top_level.txt +2 -0
  27. parityos_addons/benchmarking/__init__.py +11 -0
  28. parityos_addons/benchmarking/benchmark_compiler_runs.py +79 -0
  29. parityos_addons/benchmarking/benchmark_parityos_outputs.py +48 -0
  30. parityos_addons/benchmarking/dataframe_construction/__init__.py +0 -0
  31. parityos_addons/benchmarking/dataframe_construction/add_column.py +38 -0
  32. parityos_addons/benchmarking/dataframe_construction/benchmark_circuits.py +47 -0
  33. parityos_addons/benchmarking/dataframe_construction/benchmark_compiler_runs.py +46 -0
  34. parityos_addons/benchmarking/dataframe_construction/benchmark_problem_representations.py +52 -0
  35. parityos_addons/benchmarking/metrics/__init__.py +27 -0
  36. parityos_addons/benchmarking/metrics/circuit_metrics.py +125 -0
  37. parityos_addons/benchmarking/metrics/circuit_utils.py +37 -0
  38. parityos_addons/benchmarking/metrics/compilation_metrics.py +75 -0
  39. parityos_addons/documentation/__init__.py +0 -0
  40. parityos_addons/documentation/html/_images/hypergraph_solution_tutorial.png +0 -0
  41. parityos_addons/documentation/html/_images/hypergraph_tutorial.png +0 -0
  42. parityos_addons/documentation/html/_sources/api_reference/api_interface.rst.txt +6 -0
  43. parityos_addons/documentation/html/_sources/api_reference/base.rst.txt +14 -0
  44. parityos_addons/documentation/html/_sources/api_reference/encodings.rst.txt +11 -0
  45. parityos_addons/documentation/html/_sources/api_reference/index.rst.txt +11 -0
  46. parityos_addons/documentation/html/_sources/api_reference/parityos.rst.txt +6 -0
  47. parityos_addons/documentation/html/_sources/api_reference/parityos_addons.rst.txt +17 -0
  48. parityos_addons/documentation/html/_sources/asynchronous_submission.rst.txt +67 -0
  49. parityos_addons/documentation/html/_sources/benchmarking.rst.txt +132 -0
  50. parityos_addons/documentation/html/_sources/custom_device_models.rst.txt +221 -0
  51. parityos_addons/documentation/html/_sources/index.rst.txt +15 -0
  52. parityos_addons/documentation/html/_sources/installation.rst.txt +33 -0
  53. parityos_addons/documentation/html/_sources/parity_decoder.rst.txt +69 -0
  54. parityos_addons/documentation/html/_sources/quickstart.rst.txt +199 -0
  55. parityos_addons/documentation/html/_sources/tutorial.rst.txt +449 -0
  56. parityos_addons/documentation/html/_static/_sphinx_javascript_frameworks_compat.js +123 -0
  57. parityos_addons/documentation/html/_static/basic.css +914 -0
  58. parityos_addons/documentation/html/_static/css/badge_only.css +1 -0
  59. parityos_addons/documentation/html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  60. parityos_addons/documentation/html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  61. parityos_addons/documentation/html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  62. parityos_addons/documentation/html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  63. parityos_addons/documentation/html/_static/css/fonts/fontawesome-webfont.eot +0 -0
  64. parityos_addons/documentation/html/_static/css/fonts/fontawesome-webfont.svg +2671 -0
  65. parityos_addons/documentation/html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  66. parityos_addons/documentation/html/_static/css/fonts/fontawesome-webfont.woff +0 -0
  67. parityos_addons/documentation/html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  68. parityos_addons/documentation/html/_static/css/fonts/lato-bold-italic.woff +0 -0
  69. parityos_addons/documentation/html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  70. parityos_addons/documentation/html/_static/css/fonts/lato-bold.woff +0 -0
  71. parityos_addons/documentation/html/_static/css/fonts/lato-bold.woff2 +0 -0
  72. parityos_addons/documentation/html/_static/css/fonts/lato-normal-italic.woff +0 -0
  73. parityos_addons/documentation/html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  74. parityos_addons/documentation/html/_static/css/fonts/lato-normal.woff +0 -0
  75. parityos_addons/documentation/html/_static/css/fonts/lato-normal.woff2 +0 -0
  76. parityos_addons/documentation/html/_static/css/theme.css +4 -0
  77. parityos_addons/documentation/html/_static/doctools.js +149 -0
  78. parityos_addons/documentation/html/_static/documentation_options.js +13 -0
  79. parityos_addons/documentation/html/_static/file.png +0 -0
  80. parityos_addons/documentation/html/_static/fonts/Lato/lato-bold.eot +0 -0
  81. parityos_addons/documentation/html/_static/fonts/Lato/lato-bold.ttf +0 -0
  82. parityos_addons/documentation/html/_static/fonts/Lato/lato-bold.woff +0 -0
  83. parityos_addons/documentation/html/_static/fonts/Lato/lato-bold.woff2 +0 -0
  84. parityos_addons/documentation/html/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  85. parityos_addons/documentation/html/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  86. parityos_addons/documentation/html/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  87. parityos_addons/documentation/html/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  88. parityos_addons/documentation/html/_static/fonts/Lato/lato-italic.eot +0 -0
  89. parityos_addons/documentation/html/_static/fonts/Lato/lato-italic.ttf +0 -0
  90. parityos_addons/documentation/html/_static/fonts/Lato/lato-italic.woff +0 -0
  91. parityos_addons/documentation/html/_static/fonts/Lato/lato-italic.woff2 +0 -0
  92. parityos_addons/documentation/html/_static/fonts/Lato/lato-regular.eot +0 -0
  93. parityos_addons/documentation/html/_static/fonts/Lato/lato-regular.ttf +0 -0
  94. parityos_addons/documentation/html/_static/fonts/Lato/lato-regular.woff +0 -0
  95. parityos_addons/documentation/html/_static/fonts/Lato/lato-regular.woff2 +0 -0
  96. parityos_addons/documentation/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  97. parityos_addons/documentation/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  98. parityos_addons/documentation/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  99. parityos_addons/documentation/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  100. parityos_addons/documentation/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  101. parityos_addons/documentation/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  102. parityos_addons/documentation/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  103. parityos_addons/documentation/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  104. parityos_addons/documentation/html/_static/jquery.js +2 -0
  105. parityos_addons/documentation/html/_static/js/badge_only.js +1 -0
  106. parityos_addons/documentation/html/_static/js/theme.js +1 -0
  107. parityos_addons/documentation/html/_static/js/versions.js +228 -0
  108. parityos_addons/documentation/html/_static/language_data.js +192 -0
  109. parityos_addons/documentation/html/_static/minus.png +0 -0
  110. parityos_addons/documentation/html/_static/plus.png +0 -0
  111. parityos_addons/documentation/html/_static/pygments.css +75 -0
  112. parityos_addons/documentation/html/_static/searchtools.js +632 -0
  113. parityos_addons/documentation/html/_static/sphinx_highlight.js +154 -0
  114. parityos_addons/documentation/html/api_reference/api_interface.html +124 -0
  115. parityos_addons/documentation/html/api_reference/base.html +1262 -0
  116. parityos_addons/documentation/html/api_reference/encodings.html +352 -0
  117. parityos_addons/documentation/html/api_reference/index.html +133 -0
  118. parityos_addons/documentation/html/api_reference/parityos.html +704 -0
  119. parityos_addons/documentation/html/api_reference/parityos_addons.html +382 -0
  120. parityos_addons/documentation/html/asynchronous_submission.html +185 -0
  121. parityos_addons/documentation/html/benchmarking.html +251 -0
  122. parityos_addons/documentation/html/custom_device_models.html +337 -0
  123. parityos_addons/documentation/html/genindex.html +768 -0
  124. parityos_addons/documentation/html/index.html +128 -0
  125. parityos_addons/documentation/html/installation.html +142 -0
  126. parityos_addons/documentation/html/objects.inv +0 -0
  127. parityos_addons/documentation/html/parity_decoder.html +189 -0
  128. parityos_addons/documentation/html/py-modindex.html +193 -0
  129. parityos_addons/documentation/html/quickstart.html +324 -0
  130. parityos_addons/documentation/html/search.html +127 -0
  131. parityos_addons/documentation/html/searchindex.js +1 -0
  132. parityos_addons/documentation/html/tutorial.html +530 -0
  133. parityos_addons/documentation/show.py +24 -0
  134. parityos_addons/examples/__init__.py +0 -0
  135. parityos_addons/examples/example1.py +60 -0
  136. parityos_addons/examples/example2.py +54 -0
  137. parityos_addons/examples/example3.py +58 -0
  138. parityos_addons/examples/example4.py +70 -0
  139. parityos_addons/examples/runner.py +33 -0
  140. parityos_addons/interfaces/__init__.py +22 -0
  141. parityos_addons/interfaces/cirq_exporter.py +184 -0
  142. parityos_addons/interfaces/openqasm_exporter.py +426 -0
  143. parityos_addons/interfaces/qiskit_exporter.py +251 -0
  144. parityos_addons/qaoa/__init__.py +12 -0
  145. parityos_addons/qaoa/qaoa_scheduler.py +105 -0
  146. parityos_addons/spin_hamiltonians.py +102 -0
parityos/__init__.py ADDED
@@ -0,0 +1,15 @@
1
+ """
2
+ Parity Quantum Computing GmbH
3
+ Rennweg 1 Top 314
4
+ 6020 Innsbruck, Austria
5
+
6
+ Copyright (c) 2020-2024.
7
+ All rights reserved.
8
+
9
+ Tools to use the ParityOS cloud services.
10
+ """
11
+
12
+ from .base import Hamiltonian, ProblemRepresentation, ParityOSException, ParityOSImportError, Qubit
13
+ from .device_model import RectangularAnalogDevice, RectangularDigitalDevice
14
+ from .encodings.parityos_output import ParityOSOutput
15
+ from .compiler_client import CompilerClient
File without changes
@@ -0,0 +1,87 @@
1
+ """
2
+ Parity Quantum Computing GmbH
3
+ Rennweg 1 Top 314
4
+ 6020 Innsbruck, Austria
5
+
6
+ Copyright (c) 2020-2023.
7
+ All rights reserved.
8
+
9
+ Tools to authenticate with the ParityOS cloud services.
10
+ """
11
+
12
+ from collections.abc import Iterator
13
+ import getpass
14
+ import os
15
+ import warnings
16
+
17
+
18
+ def generate_credentials(
19
+ username: str = None,
20
+ username_variable: str = "",
21
+ password_variable: str = "",
22
+ intents: int = 3,
23
+ ) -> Iterator[dict[str, str]]:
24
+ """
25
+ Generates a series of JSON compatible dictionaries with a username and a password.
26
+ The username can be provided as an argument. Otherwise, it is taken from the given system
27
+ variable (this is tried only once), or requested from the user on the prompt.
28
+ For security reasons, the password can not be provided as an argument. It is either taken
29
+ from the given system variable (this is tried only once), or requested from the user on the
30
+ prompt.
31
+ The argument `intents` sets the maximum number of times to ask for a username or password,
32
+ either from the environment or from the prompt.
33
+ To make this generator fully non-interactive, set intents to 1 and set the correct system
34
+ variables.
35
+
36
+ :param str username: The username for the account on the server.
37
+ :param str username_variable: System variable to query for the username
38
+ :param str password_variable: System variable to query for the password
39
+ :param int intents: Maximum number of times to ask for a username or password.
40
+ """
41
+ # The credentials object allows for a number of intents to provide the password.
42
+ # First intent: get data from the environment variables or else from prompt.
43
+ username = username or _get_username(username, username_variable)
44
+ password = _get_password(password_variable=password_variable)
45
+ yield {"username": username, "password": password}
46
+
47
+ # The next intents are always interactive.
48
+ for intent in range(1, intents):
49
+ print("Login failed. Please provide the correct credentials.")
50
+ username = _get_username(username)
51
+ password = _get_password(password)
52
+ yield {"username": username, "password": password}
53
+
54
+
55
+ def _get_username(username: str = "", username_variable: str = "") -> str:
56
+ """
57
+ Ask for a username, either from the provided environment variable or on the prompt.
58
+ If a username argument is given, then this is shown as a suggestion on the prompt
59
+ and returned as the result if the user only types return.
60
+ """
61
+ if username_variable and not username:
62
+ username = os.getenv(username_variable)
63
+ if username:
64
+ return username
65
+
66
+ suggestion = f" [{username}]" if username else ""
67
+ username = input(f"ParityOS Username{suggestion}: ") or username
68
+ return username
69
+
70
+
71
+ def _get_password(password: str = "", password_variable: str = "") -> str:
72
+ """
73
+ Ask for a password, either from the provided environment variable or on the prompt.
74
+ If a password argument is given, then "***" is shown as a suggestion on the prompt
75
+ and the given value is returned as the result if the user only types return.
76
+ """
77
+ if password_variable and not password:
78
+ with warnings.catch_warnings():
79
+ warnings.simplefilter("ignore")
80
+ password = os.getenv(password_variable)
81
+
82
+ if password:
83
+ return password
84
+
85
+ suggestion = " [***]" if password else ""
86
+ password = getpass.getpass(f"ParityOS Password{suggestion}: ") or password
87
+ return password
@@ -0,0 +1,113 @@
1
+ """
2
+ Parity Quantum Computing GmbH
3
+ Rennweg 1 Top 314
4
+ 6020 Innsbruck, Austria
5
+
6
+ Copyright (c) 2020-2024.
7
+ All rights reserved.
8
+
9
+ Tools to process the results from the ParityOS cloud service.
10
+ """
11
+
12
+ from dataclasses import dataclass
13
+ from datetime import datetime
14
+ from enum import Enum
15
+ from typing import Optional, Union
16
+
17
+ from parityos.base import JSONMappingType
18
+
19
+
20
+ DateStr = Union[datetime, str] # type: TypeAlias
21
+
22
+
23
+ class CompilerRunStatus(Enum):
24
+ """
25
+ Enum for compiler run status.
26
+ """
27
+
28
+ SUBMITTED = "S"
29
+ RUNNING = "R"
30
+ COMPLETED = "C"
31
+ FAILED = "F"
32
+
33
+
34
+ @dataclass
35
+ class CompilerRun:
36
+ """
37
+ Encapsulates a compiler run; has attributes which describe relevant times
38
+ at which they were submitted, started, and eventually finished or failed
39
+ (in which case, a reason for failure is also given).
40
+
41
+ :param id: The UUID4 id of the compiler run in ParityOS cloud database.
42
+ :param submission_id: The UUID4 id of the submission which triggered compile run.
43
+ :param status: The status of the submission; see the `CompilerRunStatus` enum.
44
+ :param submitted_at: Time at which the run was queued for execution, as `datetime` object.
45
+ :param started_at: Time at which the run started being executed, as `datetime` object.
46
+ :param finished_at: Time at which the run was completed, as `datetime` object.
47
+ :param failed_at: time at which run failed
48
+ :param failure_reason: reason for which run failed
49
+ """
50
+
51
+ id: str
52
+ submission_id: str
53
+ status: Union[CompilerRunStatus, str]
54
+ submitted_at: Optional[DateStr] = None
55
+ started_at: Optional[DateStr] = None
56
+ finished_at: Optional[DateStr] = None
57
+ failed_at: Optional[DateStr] = None
58
+ failure_reason: Optional[str] = ""
59
+
60
+ def __post_init__(self):
61
+ """Convert attributes to their intended type if they were provided as strings."""
62
+ # Map the status to the corresponding Enum instance.
63
+ self.status = CompilerRunStatus(self.status)
64
+ # Map date times in string format to datetime instances
65
+ self.submitted_at = _str_to_datetime(self.submitted_at)
66
+ self.started_at = _str_to_datetime(self.started_at)
67
+ self.finished_at = _str_to_datetime(self.finished_at)
68
+ self.failed_at = _str_to_datetime(self.failed_at)
69
+
70
+ @classmethod
71
+ def from_json(cls, data: JSONMappingType) -> "Self":
72
+ """
73
+ Creates a CompilerRun object from a JSON-like data dictionary.
74
+ :return: a CompilerRun object
75
+ """
76
+ return cls(**data)
77
+
78
+ def __str__(self) -> str:
79
+ """
80
+ Return useful information about the compiler run in string format.
81
+ """
82
+ info_lines = [f"Compiler run {self.id}. ", f"Status: {self.status}"]
83
+ if self.submitted_at:
84
+ info_lines.append(f"The compiler run was submitted at {self.submitted_at.ctime()}.")
85
+
86
+ if self.started_at:
87
+ info_lines.append(f"The compilation started at {self.started_at.ctime()}.")
88
+ if self.finished_at:
89
+ duration_in_seconds = (self.finished_at - self.started_at).total_seconds()
90
+ info_lines.append(f"The compilation took {duration_in_seconds:0.2f} seconds.")
91
+
92
+ if self.failed_at:
93
+ if self.started_at:
94
+ duration_in_seconds = (self.failed_at - self.started_at).total_seconds()
95
+ info_lines.append(
96
+ f"The compilation was aborted after {duration_in_seconds:0.2f} seconds."
97
+ )
98
+ else:
99
+ info_lines.append(f"An error occurred at {self.failed_at.ctime()}.")
100
+
101
+ if self.failure_reason:
102
+ info_lines.append(self.failure_reason)
103
+
104
+ return "\n".join(info_lines)
105
+
106
+
107
+ def _str_to_datetime(date: Union[datetime, str]) -> datetime:
108
+ """Helper method to convert dates in string format to datetime instances."""
109
+ return (
110
+ datetime.fromisoformat(date.replace("Z", "+00:00"))
111
+ if date and isinstance(date, str)
112
+ else date
113
+ )
@@ -0,0 +1,139 @@
1
+ """
2
+ Parity Quantum Computing GmbH
3
+ Rennweg 1 Top 314
4
+ 6020 Innsbruck, Austria
5
+
6
+ Copyright (c) 2020-2022.
7
+ All rights reserved.
8
+
9
+ Tools to connect to the ParityOS cloud services.
10
+ """
11
+
12
+ from json.decoder import JSONDecodeError
13
+
14
+ from requests import Session, Response
15
+ from requests.adapters import HTTPAdapter
16
+ from requests.packages.urllib3.util.retry import Retry
17
+
18
+ from parityos.api_interface.authentication import generate_credentials
19
+ from parityos.api_interface.exceptions import ParityOSAuthError, ParityOSRequestError
20
+
21
+
22
+ DEFAULT_HOST = "api.parityqc.com"
23
+
24
+ # Define environment variables that can hold the credentials for the default host.
25
+ DEFAULT_ENVIRONMENT = dict(
26
+ username_variable="PARITYOS_USER",
27
+ password_variable="PARITYOS_PASS",
28
+ )
29
+ # Define the environment variables that can hold the credentials for alternative hosts.
30
+ ALTERNATIVE_ENVIRONMENT = dict(
31
+ username_variable="PARITYOS_ALTUSER",
32
+ password_variable="PARITYOS_ALTPASS",
33
+ )
34
+
35
+
36
+ class ClientBase:
37
+ """
38
+ Base class that sets up HTTP parameters (authentication, API endpoints, and so on).
39
+ It should not be used directly unless you are debugging HTTP requests,
40
+ use parityos.CompilerClient instead.
41
+ """
42
+
43
+ def __init__(
44
+ self,
45
+ username: str = None,
46
+ host: str = DEFAULT_HOST,
47
+ url_prefix: str = "v1",
48
+ http_retries: int = 3,
49
+ http_timeout: int = 10,
50
+ http_backoff_factor: float = 0.02,
51
+ intents: int = 3,
52
+ ):
53
+ """
54
+ :param str username: ParityOS id of the user.
55
+ :param str host: ParityAPI host name.
56
+ :param str url_prefix: Prefix to REST API paths, used mostly for versioning.
57
+ :param int http_retries: Number of http retries.
58
+ :param int http_timeout: Maximum time in seconds to wait for a http response.
59
+ :param int http_backoff_factor: Http exponential backoff factor.
60
+ :param int intents: Maximum number of intents with different passwords.
61
+ """
62
+ self.username = username
63
+ self.host = host
64
+ self.url_prefix = url_prefix
65
+ self.base_url = f"https://{self.host}/{self.url_prefix}"
66
+ self.http_timeout = http_timeout
67
+ self.http_retries = http_retries
68
+ self.http_backoff_factor = http_backoff_factor
69
+ self.intents = intents
70
+ self._setup_connection()
71
+
72
+ def _setup_connection(self):
73
+ """
74
+ Connects to the ParityAPI server, logs the user in and stores the session token.
75
+ """
76
+ # Credentials are instantiated here so that the password information
77
+ # is garbage collected as soon as this method terminates.
78
+ self.http = Session()
79
+ adapter = HTTPAdapter(
80
+ max_retries=Retry(total=self.http_retries, backoff_factor=self.http_backoff_factor)
81
+ )
82
+ self.http.mount("https://", adapter)
83
+ self.username, token = self._get_authentication()
84
+ # Only the username is stored in self so that the password information
85
+ # can be garbage collected.
86
+ self.http.headers.update({"Authorization": f"Token {token}"})
87
+
88
+ def _get_authentication(self) -> tuple[str, str]:
89
+ """
90
+ Log in on the server to obtain an authentication token for future requests.
91
+ """
92
+ # The credentials object allows for a number of intents to provide the password.
93
+ environment_variables = (
94
+ DEFAULT_ENVIRONMENT if self.host == DEFAULT_HOST else ALTERNATIVE_ENVIRONMENT
95
+ )
96
+ authentication_intents = generate_credentials(
97
+ self.username,
98
+ **environment_variables,
99
+ intents=self.intents,
100
+ )
101
+ username = self.username
102
+ for credentials_data in authentication_intents:
103
+ response = self.http.post(f"{self.base_url}/auth", data=credentials_data)
104
+ data = response.json()
105
+ username = credentials_data["username"]
106
+ if "token" in data:
107
+ return username, data["token"]
108
+
109
+ # No authentication intents left after failed logins
110
+ raise ParityOSAuthError(f"Failed login for user {username} on server {self.host}.")
111
+
112
+ def _send_request(self, method: str, url: str, data: dict = None) -> Response:
113
+ """
114
+ Send a http request
115
+
116
+ :param method: request method to use ('GET', 'POST', 'PUT', ... )
117
+ :param url: target url
118
+ :param data: payload data as a dictionary
119
+ :return: requests.Response object
120
+ """
121
+ try:
122
+ response = self.http.request(method, url=url, json=data, timeout=self.http_timeout)
123
+ except Exception as err:
124
+ message = f"Failed to receive valid response after at most {self.http_retries} retries."
125
+ err.args = (*err.args, message)
126
+ raise err
127
+
128
+ if response.ok:
129
+ return response
130
+ else:
131
+ try:
132
+ error_data = response.json()
133
+ except JSONDecodeError:
134
+ error_data = "None"
135
+
136
+ raise ParityOSRequestError(
137
+ f"{method} on {url}: {response.status_code}, {error_data}",
138
+ response=response,
139
+ )
@@ -0,0 +1,36 @@
1
+ """
2
+ Parity Quantum Computing GmbH
3
+ Rennweg 1 Top 314
4
+ 6020 Innsbruck, Austria
5
+
6
+ Copyright (c) 2020-2024.
7
+ All rights reserved.
8
+ """
9
+
10
+ from requests.exceptions import RequestException
11
+
12
+ from parityos.base.exceptions import ParityOSException
13
+
14
+
15
+ class ParityOSAuthError(RequestException, ValueError):
16
+ """
17
+ Exception for failed logins to the ParityAPI server.
18
+ """
19
+
20
+
21
+ class ParityOSRequestError(RequestException):
22
+ """
23
+ Exception for failed logins to the ParityAPI server.
24
+ """
25
+
26
+
27
+ class ParityOSCompilerError(ParityOSException):
28
+ """
29
+ Exception resulting from errors in the compiler on the ParityOS cloud server.
30
+ """
31
+
32
+
33
+ class ParityOSTimeoutException(ParityOSException):
34
+ """
35
+ Exception resulting from time-outs waiting for a response from the ParityOS cloud server.
36
+ """
@@ -0,0 +1,48 @@
1
+ """
2
+ Parity Quantum Computing GmbH
3
+ Rennweg 1 Top 314
4
+ 6020 Innsbruck, Austria
5
+
6
+ Copyright (c) 2020-2024.
7
+ All rights reserved.
8
+
9
+ Basic data structures to describe gates, circuits and optimization problems.
10
+ """
11
+
12
+ from .circuit import Circuit
13
+ from .constraints import ConfigurationType, EqualityConstraint, evaluate_parity, ParityConstraint
14
+ from .exceptions import ParityOSException, ParityOSImportError
15
+ from .gates import (
16
+ CCNOT,
17
+ CH,
18
+ CNOT,
19
+ CP,
20
+ CRx,
21
+ CRy,
22
+ CRz,
23
+ CY,
24
+ CZ,
25
+ DEFAULT_PARAMETER_NAME,
26
+ Gate,
27
+ H,
28
+ ISwap,
29
+ MultiControlledH,
30
+ MultiControlledRx,
31
+ MultiControlledRy,
32
+ MultiControlledRz,
33
+ Rx,
34
+ Ry,
35
+ Rz,
36
+ Rxx,
37
+ Ryy,
38
+ Rzz,
39
+ Rzzzz,
40
+ Swap,
41
+ SX,
42
+ X,
43
+ Y,
44
+ Z,
45
+ )
46
+ from .problem_representation import Hamiltonian, ProblemRepresentation
47
+ from .qubits import Qubit, QubitLabel
48
+ from .utils import json_wrap, dict_filter, JSONType, JSONMappingType, JSONLoadSaveMixin
@@ -0,0 +1,219 @@
1
+ """
2
+ Parity Quantum Computing GmbH
3
+ Rennweg 1 Top 314
4
+ 6020 Innsbruck, Austria
5
+
6
+ Copyright (c) 2020-2024.
7
+ All rights reserved.
8
+
9
+ Classes that store information on sequences of quantum gates
10
+ """
11
+
12
+ from collections.abc import Iterator, Mapping, Sequence
13
+ from math import pi
14
+ from typing import Union
15
+
16
+ from parityos.base.exceptions import ParityOSException
17
+ from parityos.base.gates import Gate, CNOT, RMixin, Rx, Ry, Rz, Rzz
18
+ from parityos.base.qubits import Qubit
19
+ from parityos.base.utils import json_wrap, JSONLoadSaveMixin, JSONType
20
+
21
+
22
+ class Circuit(JSONLoadSaveMixin, list):
23
+ """
24
+ A sequence of Gate and/or Circuit objects.
25
+ """
26
+
27
+ @property
28
+ def qubits(self) -> set[Qubit]:
29
+ """
30
+ :return: All qubits from the elements in the circuit
31
+ """
32
+ return set().union(*(element.qubits for element in self))
33
+
34
+ @property
35
+ def parameters(self) -> set[str]:
36
+ """
37
+ :return: the set of parameters (strings)
38
+ """
39
+ parameters = set()
40
+ for gate_or_circuit_element in self:
41
+ if hasattr(gate_or_circuit_element, "parameters"):
42
+ parameters.update(gate_or_circuit_element.parameters)
43
+
44
+ return parameters
45
+
46
+ def get_hermitian_conjugate(self) -> "Self":
47
+ """
48
+ Returns the Hermitian conjugate (inverse) of the circuit
49
+ :return: a new Circuit instance
50
+ """
51
+ return type(self)(element.get_hermitian_conjugate() for element in reversed(self))
52
+
53
+ def generate_flat_gate_sequence(self) -> Iterator[Gate]:
54
+ """
55
+ Generates a sequence of all gates in the circuit and its subcircuits.
56
+
57
+ :returns: A generator that loops over all gates in the circuit and its subcircuits.
58
+ """
59
+ for element in self:
60
+ if isinstance(element, Gate):
61
+ yield element
62
+ else:
63
+ yield from element.generate_flat_gate_sequence()
64
+
65
+ @classmethod
66
+ def from_json(cls, data: Sequence[Sequence[JSONType]]) -> "Self":
67
+ """
68
+ Creates a Circuit from a list of elements in json
69
+
70
+ :param data: a list of elements in json format
71
+ :return: a Circuit object
72
+ """
73
+ args = (
74
+ (
75
+ Gate.from_json(element_data)
76
+ if isinstance(element_data[0], str)
77
+ else cls.from_json(element_data)
78
+ )
79
+ for element_data in data
80
+ if element_data
81
+ )
82
+ return cls(args)
83
+
84
+ def to_json(self) -> list[JSONType]:
85
+ """
86
+ Converts the Container to json
87
+
88
+ :return: a list with the elements of the circuit in json format
89
+ """
90
+ return [json_wrap(element) for element in self]
91
+
92
+ def remap(self, context: Mapping = None, **kwargs) -> "Circuit":
93
+ """
94
+ Creates a copy of the circuit where the remap has been applied to all parametrized gates
95
+ in the circuit (see `gates.RMixin.remap` for details).
96
+
97
+ :param context: a mapping of parameter names (strings) to parameter values (number-like
98
+ objects) or to new parameter names (strings).
99
+ """
100
+ return Circuit((element.remap(context=context, **kwargs) for element in self))
101
+
102
+ def modify_angle(
103
+ self,
104
+ angle_map: Mapping[frozenset[Qubit], float],
105
+ gate_type: type[RMixin] = None,
106
+ parameter_name: str = None,
107
+ ) -> "Self":
108
+ """
109
+ Create a new circuit with the same subcircuits and gates as this one, except for the
110
+ rotation gates of the given gate type and with the given parameter_name as parameter,
111
+ for which the angle will be changed to the values given by the angle map, in function
112
+ of the qubit(s) on which the gate acts. If the qubit(s) are not included in the angle map,
113
+ then the angle is left unchanged.
114
+
115
+ If the gate type is not specified, then all rotation gates might be affected. If the
116
+ parameter name is not specified, then also gates without parameters might be affected.
117
+
118
+ :param angle_map: A mapping that provides a new angle for each of the qubit sets on which
119
+ the gates might act.
120
+ :param gate_type: Optional. If given, then only gates of this type will be updated. Other
121
+ gates will be copied into the new circuit without changes. Default is
122
+ None.
123
+ :param parameter_name: Optional. If given, then only gates with this parameter name will be
124
+ updated. Other gates will be copied into the new circuit without
125
+ changes. Default is None.
126
+
127
+ :returns: A new circuit with all the gates copied over from the current circuit, except for
128
+ selected rotation gates for which the rotation angle will have been modified.
129
+ Default is None.
130
+
131
+ """
132
+ return type(self)(
133
+ element.modify_angle(angle_map, gate_type=gate_type, parameter_name=parameter_name)
134
+ for element in self
135
+ )
136
+
137
+ def __repr__(self):
138
+ args = ", ".join(repr(element) for element in self)
139
+ return f"{self.__class__.__name__}([{args}])"
140
+
141
+ def __add__(self, other):
142
+ return type(self)(list.__add__(self, other))
143
+
144
+ def __mul__(self, other):
145
+ return type(self)(list.__mul__(self, other))
146
+
147
+ def __rmul__(self, other):
148
+ return type(self)(list.__rmul__(self, other))
149
+
150
+ def __getitem__(self, key):
151
+ # Convert slices of circuits to again to Circuits
152
+ item = list.__getitem__(self, key)
153
+ return type(self)(item) if isinstance(key, slice) else item
154
+
155
+
156
+ CircuitElement = Union[Gate, Circuit]
157
+ HALF_PI = 0.5 * pi
158
+
159
+
160
+ def convert_cnots_to_rzzs(circuit: Circuit) -> Circuit:
161
+ """
162
+ ZZ rotations instead of CNOTs.
163
+
164
+ Replaces the standards CNOTs on the optimized circuit with an equivalent implementation based on
165
+ ZZ and local rotations. The resulting circuit will contain additional subcircuits to account
166
+ for the necessary Rx, Ry and Rz rotations.
167
+
168
+ :param circuit: a circuit containing moments with CNOT gates.
169
+ :type circuit: Circuit
170
+ :return: a new circuit where all CNOTs have been replaced by ZZ and local rotations.
171
+ :rtype: Circuit
172
+ """
173
+ new_circuit = Circuit()
174
+ for subcircuit in circuit:
175
+ if not isinstance(subcircuit, Circuit):
176
+ # This situation can occur when gates and subcircuits were mixed together at the same
177
+ # level. We raise an error in this case, because this method expects gates to be grouped
178
+ # in moments (i.e. parallelizable subcircuits).
179
+ raise ParityOSException(
180
+ "Unexpected mix of gates and subcircuits encountered. Please "
181
+ "organize gates in moments (parallelizable subcircuits)."
182
+ )
183
+ elif all(isinstance(element, Gate) for element in subcircuit):
184
+ new_circuit.extend(_convert_moment(subcircuit))
185
+ else:
186
+ new_circuit.append(convert_cnots_to_rzzs(subcircuit))
187
+
188
+ return new_circuit
189
+
190
+
191
+ def _convert_moment(circuit) -> Iterator[Circuit]:
192
+ """
193
+ A helper function for convert_cnots_to_rzzs.
194
+ Lowest level circuits are expanded and have cnots turned into rzzs. This results in additional
195
+ circuits to be added before and after the moment circuit to account for the necessary Rx, Ry
196
+ and Rz rotations.
197
+
198
+ :return: a list of circuits representing the original circuit where cnots have been converted to
199
+ rzz gates.
200
+ """
201
+ before, moment, after1, after2 = Circuit(), Circuit(), Circuit(), Circuit()
202
+ # Representing a Cnot as a ZZ interaction requires the injection of a moment before and two
203
+ # moments after the original moment.
204
+ for gate in circuit:
205
+ if not isinstance(gate, CNOT):
206
+ # Copy the other gates directly to the new moment.
207
+ moment.append(gate)
208
+ else:
209
+ control, target = gate.make_args()
210
+ # Add the necessary rotation before the ZZ interaction.
211
+ before.append(Ry(target, -HALF_PI))
212
+ # Replace the CNOT with a ZZ rotation.
213
+ moment.append(Rzz(control, target, -HALF_PI))
214
+ # Add the remaining rotations after the ZZ interaction.
215
+ after1.append(Rx(target, HALF_PI))
216
+ after2.append(Rz(control, HALF_PI))
217
+ after2.append(Rz(target, HALF_PI))
218
+
219
+ return (subcircuit for subcircuit in [before, moment, after1, after2] if subcircuit)