qec 0.2.7__py3-none-any.whl → 0.3.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.
@@ -1,274 +0,0 @@
1
- import logging
2
-
3
- # Suppress debug and info messages from urllib3 and requests libraries
4
- logging.getLogger("urllib3").setLevel(logging.WARNING)
5
- logging.getLogger("requests").setLevel(logging.WARNING)
6
-
7
- from scipy.sparse import csr_matrix
8
-
9
- import requests
10
- from bs4 import BeautifulSoup
11
- import json
12
-
13
-
14
- def get_codetables_de_matrix(q, n, k, output_json_path=None, write_to_file=False):
15
- """
16
- Retrieve quantum code data from Markus Grassl's codetables.de website.
17
-
18
- This function queries the URL:
19
- ``https://codetables.de/QECC/QECC.php?q={q}&n={n}&k={k}``,
20
- attempting to fetch data for a quantum code with the specified parameters
21
- over GF(q). The HTML response is parsed to extract:
22
-
23
- - The lower bound (``d_lower``) and upper bound (``d_upper``) on the code distance.
24
- - The stabilizer matrix (as lines within a ``<pre>`` block).
25
-
26
- The stabilizer matrix is then converted into a list of rows, each containing
27
- the column indices of any '1' entries (the ``pcm``). The result is returned
28
- as a dictionary, and optionally written to a JSON file.
29
-
30
- Parameters
31
- ----------
32
- q : int
33
- The field size (e.g. 2, 4, etc.).
34
- n : int
35
- The length of the code (number of physical qubits).
36
- k : int
37
- The dimension of the code (number of logical qubits).
38
- output_json_path : str or None, optional
39
- File path to which the resulting dictionary will be written if
40
- ``write_to_file`` is set to True. If None and ``write_to_file`` is True,
41
- raises a ValueError.
42
- write_to_file : bool, optional
43
- Whether to write the resulting dictionary to a JSON file.
44
-
45
- Returns
46
- -------
47
- dict
48
- A dictionary with the fields:
49
- ``{"n", "k", "d_upper", "d_lower", "url", "pcm"}``.
50
-
51
- - ``pcm`` is a list of lists, where each inner list contains the column
52
- indices of '1's for that row of the stabilizer matrix.
53
- - ``url`` is the codetables.de URL used for the query.
54
- - ``d_upper`` and ``d_lower`` are the distance bounds, if found.
55
-
56
- Raises
57
- ------
58
- ValueError
59
- If the server response is not 200 OK, or if no valid stabilizer matrix
60
- lines could be found in the HTML (i.e., no code data for those parameters).
61
- Also raised if ``write_to_file`` is True and ``output_json_path`` is None.
62
-
63
- Notes
64
- -----
65
- - Data is sourced from `codetables.de <https://codetables.de>`__,
66
- maintained by Markus Grassl.
67
- - The function does not return an actual matrix but rather a convenient
68
- representation of it (the ``pcm``). Use ``pcm_to_csr_matrix`` or another
69
- helper to convert it into a numerical/sparse form.
70
- """
71
- url = f"https://codetables.de/QECC/QECC.php?q={q}&n={n}&k={k}"
72
- resp = requests.get(url)
73
- if resp.status_code != 200:
74
- raise ValueError(
75
- f"Failed to retrieve data (status code: {resp.status_code}). URL was: {url}"
76
- )
77
-
78
- soup = BeautifulSoup(resp.text, "html.parser")
79
-
80
- # 1) Extract lower and upper distance bounds from <table> elements
81
- lower_bound = None
82
- upper_bound = None
83
- tables = soup.find_all("table")
84
- for table in tables:
85
- rows = table.find_all("tr")
86
- for row in rows:
87
- cells = row.find_all("td")
88
- if len(cells) == 2:
89
- heading = cells[0].get_text(strip=True).lower()
90
- value = cells[1].get_text(strip=True)
91
- if "lower bound" in heading:
92
- lower_bound = value
93
- elif "upper bound" in heading:
94
- upper_bound = value
95
-
96
- # 2) Extract the stabilizer matrix lines from <pre> tags
97
- matrix_lines = []
98
- for tag in soup.find_all("pre"):
99
- text = tag.get_text()
100
- if "stabilizer matrix" in text.lower():
101
- lines = text.splitlines()
102
- capture = False
103
- for line in lines:
104
- if "stabilizer matrix" in line.lower():
105
- capture = True
106
- continue
107
- if capture:
108
- # Stop at 'last modified:' or if the line is empty
109
- if "last modified:" in line.lower():
110
- break
111
- if line.strip() != "":
112
- matrix_lines.append(line.strip())
113
-
114
- if not matrix_lines:
115
- raise ValueError(f"No valid stabilizer matrix found at {url}")
116
-
117
- # 3) Convert lines -> list of column-index lists
118
- pcm_list = []
119
- for line in matrix_lines:
120
- line = line.strip().strip("[]").replace("|", " ")
121
- elements = line.split()
122
- row_cols = [i for i, val in enumerate(elements) if val == "1"]
123
- pcm_list.append(row_cols)
124
-
125
- if not pcm_list:
126
- raise ValueError(f"No valid rows containing '1' found at {url}")
127
-
128
- # 4) Build final dictionary
129
- result_dict = {
130
- "n": n,
131
- "k": k,
132
- "d_upper": upper_bound,
133
- "d_lower": lower_bound,
134
- "url": url,
135
- "pcm": pcm_list,
136
- }
137
-
138
- # 5) Optionally write to JSON file
139
- if write_to_file:
140
- if output_json_path is None:
141
- raise ValueError("output_json_path must be provided if write_to_file=True.")
142
- with open(output_json_path, "w") as out_file:
143
- json.dump(result_dict, out_file, indent=2)
144
-
145
- return result_dict
146
-
147
-
148
- def pcm_to_csr_matrix(pcm, num_cols=None):
149
- """
150
- Convert a "pcm" to a SciPy CSR matrix.
151
-
152
- Each inner list of ``pcm`` is interpreted as the column indices in which
153
- row `i` has a value of 1. The resulting CSR matrix will thus have as many
154
- rows as ``len(pcm)``. The number of columns can either be:
155
-
156
- - Inferred automatically (``num_cols=None``) by taking 1 + max(column index).
157
- - Specified by the user. If a column index is >= num_cols, a ValueError is raised.
158
-
159
- Parameters
160
- ----------
161
- pcm : list of lists of int
162
- Each element ``pcm[i]`` is a list of column indices where row i has '1'.
163
- num_cols : int or None, optional
164
- The desired number of columns (width of the matrix).
165
- If None, the width is auto-detected from the maximum column index.
166
-
167
- Returns
168
- -------
169
- csr_matrix
170
- A sparse matrix of shape ``(len(pcm), num_cols)``.
171
-
172
- Raises
173
- ------
174
- ValueError
175
- If any column index exceeds the specified ``num_cols``.
176
- Also raised if no rows or invalid columns exist.
177
-
178
- See Also
179
- --------
180
- get_codetables_de_matrix : Returns a dictionary with ``pcm`` field from codetables.de.
181
-
182
- Notes
183
- -----
184
- Data is typically retrieved from `codetables.de <https://codetables.de>`__
185
- and fed into this function to produce a numerical/sparse representation.
186
- """
187
- if not pcm:
188
- # No rows at all => shape (0, num_cols) or (0, 0) if num_cols is None
189
- if num_cols is None:
190
- return csr_matrix((0, 0), dtype=int)
191
- else:
192
- return csr_matrix((0, num_cols), dtype=int)
193
-
194
- row_indices = []
195
- col_indices = []
196
- data = []
197
-
198
- max_col_found = -1
199
-
200
- # Collect row/col for each '1' entry
201
- for row_idx, col_list in enumerate(pcm):
202
- for c in col_list:
203
- row_indices.append(row_idx)
204
- col_indices.append(c)
205
- data.append(1)
206
- if c > max_col_found:
207
- max_col_found = c
208
-
209
- num_rows = len(pcm)
210
-
211
- # Auto-detect columns if not specified
212
- if num_cols is None:
213
- num_cols = max_col_found + 1
214
- else:
215
- # If the user specified num_cols, ensure the data fits
216
- if max_col_found >= num_cols:
217
- raise ValueError(
218
- f"Column index {max_col_found} is out of range for a matrix of width {num_cols}."
219
- )
220
-
221
- return csr_matrix(
222
- (data, (row_indices, col_indices)), shape=(num_rows, num_cols), dtype=int
223
- )
224
-
225
-
226
- def load_codetables_de_matrix_from_json(json_data):
227
- """
228
- Construct a CSR matrix from a codetables.de JSON/dict output.
229
-
230
- This function takes either a dictionary (as returned by
231
- ``get_codetables_de_matrix``) or a JSON string that decodes to the same
232
- structure, and converts the ``pcm`` field into a SciPy CSR matrix.
233
-
234
- Parameters
235
- ----------
236
- json_data : dict or str
237
- Must contain at least the following keys:
238
- ``{"n", "k", "d_upper", "d_lower", "url", "pcm"}``.
239
- - ``pcm`` is a list of lists of column indices.
240
-
241
- Returns
242
- -------
243
- csr_matrix
244
- The stabilizer matrix in CSR format.
245
- dict
246
- The original dictionary that was passed in (or parsed from JSON).
247
-
248
- Raises
249
- ------
250
- ValueError
251
- If ``json_data`` is not a dict, if it cannot be parsed into one,
252
- or if required keys are missing.
253
-
254
- Notes
255
- -----
256
- - Data is assumed to come from Markus Grassl's `codetables.de <https://codetables.de>`__.
257
- - This utility is helpful when the data is stored or transmitted in JSON form
258
- but needs to be loaded back into a matrix representation for further processing.
259
- """
260
- if isinstance(json_data, str):
261
- json_data = json.loads(json_data)
262
-
263
- if not isinstance(json_data, dict):
264
- raise ValueError(
265
- "json_data must be a dict or a JSON string that decodes to a dict."
266
- )
267
-
268
- required_keys = {"n", "k", "d_upper", "d_lower", "url", "pcm"}
269
- if not required_keys.issubset(json_data.keys()):
270
- raise ValueError(f"JSON data missing required keys: {required_keys}")
271
-
272
- pcm = json_data["pcm"]
273
- sparse_matrix = pcm_to_csr_matrix(pcm)
274
- return sparse_matrix, json_data
@@ -1,64 +0,0 @@
1
- import numpy as np
2
- import scipy.sparse
3
-
4
-
5
- def convert_to_binary_scipy_sparse(
6
- matrix: np.typing.ArrayLike,
7
- ) -> scipy.sparse.csr_matrix:
8
- """
9
- Convert and validate a matrix as a sparse binary matrix in CSR format.
10
-
11
- This function checks whether all elements of the input matrix are binary (0 or 1).
12
- If the input is not already a sparse matrix, it converts it to a CSR (Compressed Sparse Row) matrix.
13
-
14
- Parameters
15
- ----------
16
- matrix : array-like
17
- Input matrix of shape (M, N). Can be a dense array-like or any SciPy sparse matrix format.
18
-
19
- Returns
20
- -------
21
- scipy.sparse.csr_matrix
22
- Binary sparse matrix in CSR format, of shape (M, N).
23
-
24
- Raises
25
- ------
26
- ValueError
27
- If the input matrix has elements outside {0, 1}.
28
- TypeError
29
- If the input is not array-like.
30
-
31
- Examples
32
- --------
33
- >>> import numpy as np
34
- >>> from scipy.sparse import csr_matrix
35
- >>> from qec.utils.sparse_binary_utils import convert_to_binary_scipy_sparse
36
- >>> mat = np.array([[0, 1], [1, 0]])
37
- >>> convert_to_binary_scipy_sparse(mat).toarray()
38
- array([[0, 1],
39
- [1, 0]])
40
-
41
- >>> mat = csr_matrix([[0, 1], [1, 0]])
42
- >>> convert_to_binary_scipy_sparse(mat).toarray()
43
- array([[0, 1],
44
- [1, 0]])
45
-
46
- >>> mat = np.array([[0, 2], [1, 0]])
47
- >>> convert_to_binary_scipy_sparse(mat)
48
- Traceback (most recent call last):
49
- ...
50
- ValueError: All elements of the input matrix must be binary.
51
- """
52
- if not isinstance(matrix, (np.ndarray, list, scipy.sparse.spmatrix)):
53
- raise TypeError("Input must be array-like.")
54
-
55
- if not isinstance(matrix, scipy.sparse.spmatrix):
56
- matrix = scipy.sparse.csr_matrix(matrix, dtype=np.uint8)
57
-
58
- if not matrix.dtype == np.uint8:
59
- matrix = matrix.astype(np.uint8)
60
-
61
- if not np.all(np.isin(matrix.data, [0, 1])):
62
- raise ValueError("All elements of the input matrix must be binary.")
63
-
64
- return matrix
@@ -1,18 +0,0 @@
1
- qec/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- qec/code_constructions/__init__.py,sha256=AyEYcahGs_4C8nqSUhoYmZNBt1TzuzVPZjNN1FErRyQ,118
3
- qec/code_constructions/css_code.py,sha256=nIaC24QhQwrmWQNhmX-X4TzlkmNAYoxN0feTdWjhswo,32376
4
- qec/code_constructions/hgp_code.py,sha256=r5E_tEilRRJWDXrMbNAbplf-N5Y0XS7VUoWWTEjh9BY,11098
5
- qec/code_constructions/stabilizer_code.py,sha256=I5u8JKZu88ioC4E2nBJ-00xCmnL8nU6kdAvwYOfmNRk,22138
6
- qec/code_instances/__init__.py,sha256=z6jOPjekDIx0jgbRFThI95zUzLzjl9Dh89RBzxsT_BE,43
7
- qec/code_instances/five_qubit_code.py,sha256=ZHyusTEnnnmUv4QxPLXQSKbEQv2QOoBqn2V9N4SgrQE,2177
8
- qec/codetables_de/__init__.py,sha256=dQBgkBK_DlnI9OrOcfarM7HUbj9NKyO-9QSvItD2cyY,40
9
- qec/codetables_de/codetables_de.py,sha256=SdOaS7OTMt76uLa1GJXGydMTmwJdNwTDnQyD4SBQDIM,3626
10
- qec/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- qec/utils/binary_pauli_utils.py,sha256=BSlngYDdRICu0aVu4u_m0bvLicohORyGxfk5eRER7TQ,13245
12
- qec/utils/codetables_de_utils.py,sha256=S1wcVGJkkASQQ5s71QAsYBmpyE-3xTb6UsvgMfQtuiw,9469
13
- qec/utils/sparse_binary_utils.py,sha256=Y9xfGKzOGFiVTyhb6iF6N7-5oMY6Ah9oLrnv8HhSBHA,1965
14
- qec-0.2.7.dist-info/LICENSE,sha256=1b_xwNz1znYBfEaCL6pN2gNBAn8pQIjDRs_UhDp1EJI,1066
15
- qec-0.2.7.dist-info/METADATA,sha256=KJk3mjCfJkluDMXt7-jh3lhPMpd_bvX3e3KPmKurRbo,4611
16
- qec-0.2.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
17
- qec-0.2.7.dist-info/top_level.txt,sha256=d8l_7pJ5u9uWdviNp0FUK-j8VPZqywkDek7qa4NDank,4
18
- qec-0.2.7.dist-info/RECORD,,
File without changes
File without changes