QuLab 2.11.15__py3-none-any.whl → 2.12.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.
- qulab/__init__.py +9 -6
- qulab/executor/registry.py +18 -13
- qulab/executor/template.py +15 -20
- qulab/monitor/dataset.py +4 -4
- qulab/monitor/event_queue.py +13 -11
- qulab/monitor/mainwindow.py +20 -18
- qulab/monitor/monitor.py +23 -13
- qulab/monitor/ploter.py +9 -7
- qulab/monitor/qt_compat.py +2 -1
- qulab/monitor/toolbar.py +3 -3
- qulab/version.py +1 -1
- qulab/visualization/_autoplot.py +19 -19
- qulab/visualization/plot_circ.py +5 -5
- qulab/visualization/plot_layout.py +96 -8
- {qulab-2.11.15.dist-info → qulab-2.12.0.dist-info}/METADATA +1 -1
- {qulab-2.11.15.dist-info → qulab-2.12.0.dist-info}/RECORD +20 -20
- {qulab-2.11.15.dist-info → qulab-2.12.0.dist-info}/WHEEL +0 -0
- {qulab-2.11.15.dist-info → qulab-2.12.0.dist-info}/entry_points.txt +0 -0
- {qulab-2.11.15.dist-info → qulab-2.12.0.dist-info}/licenses/LICENSE +0 -0
- {qulab-2.11.15.dist-info → qulab-2.12.0.dist-info}/top_level.txt +0 -0
qulab/__init__.py
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
from qlisp import (CR, CX, CZ, SWAP, A, B, BellPhiM, BellPhiP, BellPsiM,
|
2
2
|
BellPsiP, H, S, Sdag, SQiSWAP, T, Tdag, U, Unitary2Angles,
|
3
|
-
applySeq
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
applySeq)
|
4
|
+
from qlisp import draw as draw_qlisp
|
5
|
+
from qlisp import (fSim, iSWAP, kak_decomposition, kak_vector, make_immutable,
|
6
|
+
measure, phiminus, phiplus, psiminus, psiplus,
|
7
|
+
regesterGateMatrix, rfUnitary, seq2mat, sigmaI, sigmaM,
|
8
|
+
sigmaP, sigmaX, sigmaY, sigmaZ, synchronize_global_phase)
|
8
9
|
from qlispc import (COMMAND, FREE, NOTSET, PUSH, READ, SYNC, TRIG, WRITE,
|
9
10
|
compile, get_arch, libraries, mapping_qubits,
|
10
11
|
register_arch)
|
@@ -30,4 +31,6 @@ from .executor.template import VAR
|
|
30
31
|
from .executor.utils import debug_analyze
|
31
32
|
from .scan import Scan, get_record, load_record, lookup, lookup_list
|
32
33
|
from .version import __version__
|
33
|
-
from .visualization import autoplot
|
34
|
+
from .visualization import autoplot, plot_mat
|
35
|
+
from .visualization.plot_layout import draw as draw_layout
|
36
|
+
from .visualization.plot_layout import fill_layout
|
qulab/executor/registry.py
CHANGED
@@ -2,7 +2,7 @@ import copy
|
|
2
2
|
import importlib
|
3
3
|
import os
|
4
4
|
import sys
|
5
|
-
from typing import Any
|
5
|
+
from typing import Any, Callable, cast
|
6
6
|
|
7
7
|
from ..cli.config import get_config_value
|
8
8
|
from .storage import Report, save_item
|
@@ -66,7 +66,7 @@ def _export_config() -> dict:
|
|
66
66
|
return parameters
|
67
67
|
|
68
68
|
|
69
|
-
def _clear_config():
|
69
|
+
def _clear_config() -> None:
|
70
70
|
import pickle
|
71
71
|
|
72
72
|
try:
|
@@ -142,13 +142,13 @@ def set_config_api(query_method,
|
|
142
142
|
|
143
143
|
|
144
144
|
def _init():
|
145
|
-
code = get_config_value("code", str, default=None)
|
145
|
+
code = cast(str, get_config_value("code", str, default=None))
|
146
146
|
if code is not None:
|
147
147
|
code = os.path.expanduser(code)
|
148
148
|
if code not in sys.path:
|
149
149
|
sys.path.insert(0, code)
|
150
150
|
|
151
|
-
api = get_config_value('api', str, None)
|
151
|
+
api = cast(str, get_config_value('api', str, None))
|
152
152
|
if api is not None:
|
153
153
|
api = importlib.import_module(api)
|
154
154
|
set_config_api(api.query_config, api.update_config, api.delete_config,
|
@@ -283,29 +283,34 @@ class RegistrySnapshot:
|
|
283
283
|
class Registry():
|
284
284
|
|
285
285
|
def __init__(self):
|
286
|
-
self.api
|
287
|
-
|
286
|
+
self.api: dict[str, Callable] = {
|
287
|
+
'query': query_config,
|
288
|
+
'update': update_config,
|
289
|
+
'delete': delete_config,
|
290
|
+
'export': export_config,
|
291
|
+
'clear': clear_config, # type: ignore
|
292
|
+
}
|
288
293
|
|
289
294
|
def query(self, key: str) -> Any:
|
290
|
-
return self.api[
|
295
|
+
return self.api['query'](key)
|
291
296
|
|
292
297
|
def get(self, key: str) -> Any:
|
293
298
|
return self.query(key)
|
294
299
|
|
295
300
|
def export(self) -> dict[str, dict[str, Any]]:
|
296
|
-
return self.api[
|
301
|
+
return self.api['export']()
|
297
302
|
|
298
303
|
def set(self, key: str, value: Any):
|
299
|
-
return self.api[
|
304
|
+
return self.api['update']({key: value})
|
300
305
|
|
301
306
|
def delete(self, key: str):
|
302
|
-
return self.api[
|
307
|
+
return self.api['delete'](key)
|
303
308
|
|
304
|
-
def clear(self):
|
305
|
-
return self.api[
|
309
|
+
def clear(self) -> None:
|
310
|
+
return self.api['clear']()
|
306
311
|
|
307
312
|
def update(self, parameters: dict[str, Any]):
|
308
|
-
return self.api[
|
313
|
+
return self.api['update'](parameters)
|
309
314
|
|
310
315
|
def snapshot(self) -> RegistrySnapshot:
|
311
316
|
return RegistrySnapshot(self.export())
|
qulab/executor/template.py
CHANGED
@@ -6,7 +6,7 @@ import pickle
|
|
6
6
|
import re
|
7
7
|
import string
|
8
8
|
import textwrap
|
9
|
-
from typing import Any
|
9
|
+
from typing import Any, cast
|
10
10
|
|
11
11
|
_notset = object()
|
12
12
|
|
@@ -14,8 +14,7 @@ _notset = object()
|
|
14
14
|
def VAR(name: str, /, *, default: Any = _notset) -> Any:
|
15
15
|
if default is _notset:
|
16
16
|
raise TemplateKeyError(
|
17
|
-
f"The variable '{name}' is not provided in mapping."
|
18
|
-
)
|
17
|
+
f"The variable '{name}' is not provided in mapping.")
|
19
18
|
else:
|
20
19
|
return default
|
21
20
|
|
@@ -60,20 +59,22 @@ class TemplateVarExtractor(ast.NodeVisitor):
|
|
60
59
|
def visit_Constant(self, node):
|
61
60
|
if isinstance(node.value, str):
|
62
61
|
self._process_string(node.value, node.lineno, node.col_offset,
|
63
|
-
|
62
|
+
cast(int, node.end_lineno),
|
63
|
+
cast(int, node.end_col_offset))
|
64
64
|
|
65
65
|
def visit_JoinedStr(self, node):
|
66
66
|
for value in node.values:
|
67
67
|
if isinstance(value, ast.Constant) and isinstance(
|
68
68
|
value.value, str):
|
69
69
|
self._process_string(value.value, value.lineno,
|
70
|
-
value.col_offset,
|
71
|
-
value.
|
70
|
+
value.col_offset,
|
71
|
+
cast(int, value.end_lineno),
|
72
|
+
cast(int, value.end_col_offset))
|
72
73
|
self.generic_visit(node)
|
73
74
|
|
74
75
|
def visit_FunctionDef(self, node):
|
75
76
|
if node.name == 'VAR':
|
76
|
-
self.var_func_def = (node.lineno, node.end_lineno)
|
77
|
+
self.var_func_def = (node.lineno, cast(int, node.end_lineno))
|
77
78
|
self.generic_visit(node)
|
78
79
|
|
79
80
|
def visit_Call(self, node):
|
@@ -81,15 +82,11 @@ class TemplateVarExtractor(ast.NodeVisitor):
|
|
81
82
|
arg = node.args[0]
|
82
83
|
if not isinstance(arg, ast.Constant) or not isinstance(
|
83
84
|
arg.value, str):
|
84
|
-
raise SyntaxError(
|
85
|
-
|
86
|
-
f" {self.fname}:{node.lineno}"
|
87
|
-
)
|
85
|
+
raise SyntaxError(f"Argument of VAR function must be a string."
|
86
|
+
f" {self.fname}:{node.lineno}")
|
88
87
|
if len(node.args) != 1:
|
89
|
-
raise SyntaxError(
|
90
|
-
|
91
|
-
f" {self.fname}:{node.lineno}"
|
92
|
-
)
|
88
|
+
raise SyntaxError(f"VAR function only accept one argument."
|
89
|
+
f" {self.fname}:{node.lineno}")
|
93
90
|
default = _notset
|
94
91
|
for k in node.keywords:
|
95
92
|
if k.arg == 'default':
|
@@ -105,8 +102,7 @@ class TemplateVarExtractor(ast.NodeVisitor):
|
|
105
102
|
else:
|
106
103
|
raise SyntaxError(
|
107
104
|
f"VAR function only accept keyword argument 'default'."
|
108
|
-
f" {self.fname}:{node.lineno}"
|
109
|
-
)
|
105
|
+
f" {self.fname}:{node.lineno}")
|
110
106
|
|
111
107
|
if default is _notset:
|
112
108
|
# new_node = ast.Subscript(value=ast.Name(id="__VAR",
|
@@ -116,8 +112,7 @@ class TemplateVarExtractor(ast.NodeVisitor):
|
|
116
112
|
if arg.value not in self.mapping:
|
117
113
|
raise TemplateKeyError(
|
118
114
|
f"The variable '{arg.value}' is not provided in mapping."
|
119
|
-
f" {self.fname}:{node.lineno}"
|
120
|
-
)
|
115
|
+
f" {self.fname}:{node.lineno}")
|
121
116
|
self.replacements[(node.lineno, node.end_lineno,
|
122
117
|
node.col_offset,
|
123
118
|
node.end_col_offset)] = ('VAR', arg.value,
|
@@ -174,7 +169,7 @@ class TemplateVarExtractor(ast.NodeVisitor):
|
|
174
169
|
|
175
170
|
|
176
171
|
def inject_mapping(source: str, mapping: dict[str, Any],
|
177
|
-
fname: str) ->
|
172
|
+
fname: str) -> tuple[str, str]:
|
178
173
|
hash_str, mapping_code = encode_mapping(mapping)
|
179
174
|
|
180
175
|
tree = ast.parse(source)
|
qulab/monitor/dataset.py
CHANGED
@@ -10,7 +10,7 @@ contain multiple named columns of numerical data.
|
|
10
10
|
"""
|
11
11
|
|
12
12
|
from collections import defaultdict, deque
|
13
|
-
from typing import Union, Sequence
|
13
|
+
from typing import Union, Sequence, cast
|
14
14
|
|
15
15
|
from .config import ROLL_BUFFER_SIZE
|
16
16
|
|
@@ -126,10 +126,10 @@ class Dataset:
|
|
126
126
|
return
|
127
127
|
try:
|
128
128
|
# Test if dataframe is a list of lists (trace data)
|
129
|
-
iter(dataframe[0])
|
130
|
-
self._append_traces(dataframe)
|
129
|
+
iter(dataframe[0]) # type: ignore
|
130
|
+
self._append_traces(cast(Sequence[Sequence[Number]], dataframe))
|
131
131
|
except TypeError:
|
132
|
-
self._append_points(dataframe)
|
132
|
+
self._append_points(cast(Sequence[Number], dataframe))
|
133
133
|
|
134
134
|
def roll(self) -> None:
|
135
135
|
"""
|
qulab/monitor/event_queue.py
CHANGED
@@ -70,14 +70,16 @@ class EventQueue:
|
|
70
70
|
if not isinstance(event, tuple):
|
71
71
|
raise ValueError("Queue event must be a tuple")
|
72
72
|
if len(event) != 2:
|
73
|
-
raise ValueError(
|
74
|
-
|
73
|
+
raise ValueError(
|
74
|
+
"Queue event must contain exactly two elements (command, data)"
|
75
|
+
)
|
76
|
+
|
75
77
|
command, data = event
|
76
78
|
if not isinstance(command, str):
|
77
79
|
raise ValueError("Command must be a string")
|
78
|
-
|
80
|
+
|
79
81
|
self.handle(command, data)
|
80
|
-
|
82
|
+
|
81
83
|
except (ValueError, AssertionError) as error:
|
82
84
|
warnings.warn(f"Invalid event format: {error}")
|
83
85
|
continue
|
@@ -103,25 +105,25 @@ class EventQueue:
|
|
103
105
|
case "PN": # Set point data column names
|
104
106
|
self.point_dataset.set_column_names(data)
|
105
107
|
self.toolbar.refresh_comb()
|
106
|
-
|
108
|
+
|
107
109
|
case "TN": # Set trace data column names
|
108
110
|
self.trace_dataset.set_column_names(data)
|
109
111
|
self.toolbar.refresh_comb()
|
110
|
-
|
112
|
+
|
111
113
|
case "PD": # Append point data
|
112
114
|
self.point_dataset.append(data)
|
113
|
-
|
115
|
+
|
114
116
|
case "TD": # Append trace data
|
115
117
|
self.trace_dataset.append(data)
|
116
|
-
|
118
|
+
|
117
119
|
case "ROLL": # Create new data frame
|
118
120
|
self.point_dataset.roll()
|
119
|
-
|
121
|
+
|
120
122
|
case "PXY": # Update point plot configuration
|
121
123
|
self.toolbar.set_point_text(data)
|
122
|
-
|
124
|
+
|
123
125
|
case "TXY": # Update trace plot configuration
|
124
126
|
self.toolbar.set_trace_text(data)
|
125
|
-
|
127
|
+
|
126
128
|
case _:
|
127
129
|
warnings.warn(f"Unknown command: {command}")
|
qulab/monitor/mainwindow.py
CHANGED
@@ -7,15 +7,16 @@ interactive features like axis linking and data transformation.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from multiprocessing import Queue
|
10
|
-
from typing import Literal
|
10
|
+
from typing import Literal, cast
|
11
11
|
|
12
|
-
from .config import
|
12
|
+
from .config import ROLL_INDICES, STYLE, TRANSFORMS
|
13
13
|
from .dataset import Dataset
|
14
14
|
from .event_queue import EventQueue
|
15
15
|
from .ploter import PlotWidget
|
16
|
-
from .qt_compat import
|
17
|
-
|
18
|
-
|
16
|
+
from .qt_compat import QtCore # type: ignore
|
17
|
+
from .qt_compat import QtWidgets # type: ignore
|
18
|
+
from .qt_compat import (BottomDockWidgetArea, ScrollBarAlwaysOff,
|
19
|
+
ScrollBarAlwaysOn, TopDockWidgetArea)
|
19
20
|
from .toolbar import ToolBar
|
20
21
|
|
21
22
|
|
@@ -50,13 +51,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
50
51
|
self.plot_minimum_height = plot_minimum_height
|
51
52
|
self.plot_widgets: list[PlotWidget] = []
|
52
53
|
self.plot_colors = plot_colors
|
53
|
-
|
54
|
+
|
54
55
|
# Initialize components
|
55
56
|
self.toolbar = ToolBar()
|
56
57
|
self.trace_data_box = Dataset()
|
57
58
|
self.point_data_box = Dataset()
|
58
59
|
self.queue = EventQueue(queue, self.toolbar, self.point_data_box,
|
59
|
-
|
60
|
+
self.trace_data_box)
|
60
61
|
|
61
62
|
self.init_ui()
|
62
63
|
|
@@ -70,7 +71,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
70
71
|
self.setStyleSheet(STYLE)
|
71
72
|
self.setMinimumHeight(500)
|
72
73
|
self.setMinimumWidth(700)
|
73
|
-
|
74
|
+
|
74
75
|
# Create scroll area
|
75
76
|
self.scroll = QtWidgets.QScrollArea()
|
76
77
|
self.widget = QtWidgets.QWidget()
|
@@ -100,7 +101,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
100
101
|
@property
|
101
102
|
def mode(self) -> Literal["P", "T"]:
|
102
103
|
"""Current plotting mode (Points or Traces)."""
|
103
|
-
return self.toolbar.mode
|
104
|
+
return cast(Literal["P", "T"], self.toolbar.mode)
|
104
105
|
|
105
106
|
@property
|
106
107
|
def dataset(self) -> Dataset:
|
@@ -119,7 +120,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
119
120
|
plot_count = len(self.plot_widgets)
|
120
121
|
plot_widget = PlotWidget(self.plot_minimum_height, self.plot_colors)
|
121
122
|
self.plot_widgets.append(plot_widget)
|
122
|
-
|
123
|
+
|
123
124
|
grid_row = plot_count // self.num_columns
|
124
125
|
grid_col = plot_count % self.num_columns
|
125
126
|
self.layout.addWidget(plot_widget, grid_row + 1, grid_col)
|
@@ -175,9 +176,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
175
176
|
|
176
177
|
def do_link(self):
|
177
178
|
"""Link plots that share the same X or Y axis."""
|
178
|
-
same_x_axis = {}
|
179
|
+
same_x_axis: dict[str, list[int]] = {}
|
179
180
|
xy_pairs = self.toolbar.xypairs
|
180
|
-
|
181
|
+
|
181
182
|
# Group plots by X axis
|
182
183
|
for idx, (x_name, y_name) in enumerate(xy_pairs):
|
183
184
|
if x_name not in same_x_axis:
|
@@ -250,19 +251,20 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
250
251
|
if self.dataset.dirty or self.toolbar.xyfm_dirty or needs_rescale:
|
251
252
|
self.dataset.dirty = False
|
252
253
|
self.toolbar.xyfm_dirty = False
|
253
|
-
|
254
|
+
|
254
255
|
# Update plot data
|
255
256
|
for plot_widget in self.plot_widgets:
|
256
|
-
x_transform = TRANSFORMS[self.toolbar.fx]
|
257
|
-
y_transform = TRANSFORMS[self.toolbar.fy]
|
258
|
-
|
257
|
+
x_transform = TRANSFORMS[cast(str, self.toolbar.fx)]
|
258
|
+
y_transform = TRANSFORMS[cast(str, self.toolbar.fy)]
|
259
|
+
|
259
260
|
for idx in ROLL_INDICES:
|
260
|
-
x_data, y_data = self.dataset.get_data(
|
261
|
+
x_data, y_data = self.dataset.get_data(
|
262
|
+
idx, plot_widget.x_name, plot_widget.y_name)
|
261
263
|
data_length = min(len(x_data), len(y_data))
|
262
264
|
x_data = x_transform(x_data[:data_length], 0)
|
263
265
|
y_data = y_transform(y_data[:data_length], 0)
|
264
266
|
plot_widget.set_data(idx, x_data, y_data)
|
265
|
-
|
267
|
+
|
266
268
|
plot_widget.update()
|
267
269
|
if needs_rescale:
|
268
270
|
plot_widget.auto_range()
|
qulab/monitor/monitor.py
CHANGED
@@ -11,6 +11,8 @@ Classes:
|
|
11
11
|
|
12
12
|
import multiprocessing as mp
|
13
13
|
import sys
|
14
|
+
from typing import cast
|
15
|
+
|
14
16
|
import zmq
|
15
17
|
|
16
18
|
# try:
|
@@ -33,10 +35,11 @@ def main(data_queue: mp.Queue,
|
|
33
35
|
plot_colors: List of RGB color tuples for plot lines
|
34
36
|
"""
|
35
37
|
from .mainwindow import MainWindow
|
36
|
-
from .qt_compat import QtWidgets
|
38
|
+
from .qt_compat import QtWidgets # type: ignore
|
37
39
|
|
38
40
|
app = QtWidgets.QApplication(sys.argv)
|
39
|
-
main_window = MainWindow(data_queue, num_columns, minimum_height,
|
41
|
+
main_window = MainWindow(data_queue, num_columns, minimum_height,
|
42
|
+
plot_colors)
|
40
43
|
sys.exit(app.exec())
|
41
44
|
|
42
45
|
|
@@ -71,8 +74,8 @@ class MonitorUI:
|
|
71
74
|
return
|
72
75
|
self.queue = mp.Queue(20)
|
73
76
|
self.process = mp.Process(target=main,
|
74
|
-
|
75
|
-
|
77
|
+
args=(self.queue, self.number_of_columns,
|
78
|
+
self.minimum_height, self.colors))
|
76
79
|
self.process.start()
|
77
80
|
|
78
81
|
def _put(self, message: tuple) -> None:
|
@@ -119,18 +122,19 @@ class MonitorUI:
|
|
119
122
|
|
120
123
|
def is_alive(self) -> bool:
|
121
124
|
"""Check if the monitoring process is running."""
|
122
|
-
return self.process.is_alive()
|
125
|
+
return self.process is not None and self.process.is_alive()
|
123
126
|
|
124
127
|
def __del__(self):
|
125
128
|
"""Clean up resources when the Monitor object is deleted."""
|
126
129
|
try:
|
127
|
-
self.process.kill()
|
130
|
+
cast(mp.Process, self.process).kill()
|
128
131
|
except:
|
129
132
|
pass
|
130
133
|
|
131
134
|
|
132
135
|
class Monitor:
|
133
|
-
|
136
|
+
|
137
|
+
def __init__(self, address: str = "127.0.0.1", port: int = 5555):
|
134
138
|
self.context = zmq.Context()
|
135
139
|
self.socket = self.context.socket(zmq.REQ)
|
136
140
|
self.socket.connect(f"tcp://{address}:{port}")
|
@@ -174,7 +178,11 @@ class Monitor:
|
|
174
178
|
|
175
179
|
|
176
180
|
class MonitorServer:
|
177
|
-
|
181
|
+
|
182
|
+
def __init__(self,
|
183
|
+
address: str = "*",
|
184
|
+
port: int = 5555,
|
185
|
+
number_of_columns: int = 4,
|
178
186
|
minimum_height: int = 400,
|
179
187
|
colors: list[tuple[int, int, int]] = []):
|
180
188
|
self.address = address
|
@@ -189,8 +197,9 @@ class MonitorServer:
|
|
189
197
|
def _run(self):
|
190
198
|
try:
|
191
199
|
# Create Monitor instance in the child process
|
192
|
-
self.monitor = MonitorUI(self.number_of_columns,
|
193
|
-
|
200
|
+
self.monitor = MonitorUI(self.number_of_columns,
|
201
|
+
self.minimum_height, self.colors)
|
202
|
+
|
194
203
|
# Create ZMQ context and socket in the child process
|
195
204
|
self.context = zmq.Context()
|
196
205
|
self.socket = self.context.socket(zmq.REP)
|
@@ -253,12 +262,13 @@ def get_monitor(auto_open: bool = True) -> MonitorUI:
|
|
253
262
|
if auto_open and (_monitor is None or not _monitor.is_alive()):
|
254
263
|
_monitor = MonitorUI()
|
255
264
|
|
256
|
-
return _monitor
|
265
|
+
return cast(MonitorUI, _monitor)
|
257
266
|
|
258
267
|
|
259
268
|
if __name__ == "__main__":
|
260
269
|
# Example usage and testing code
|
261
270
|
import time
|
271
|
+
|
262
272
|
import numpy as np
|
263
273
|
|
264
274
|
# Example 1: Using Monitor directly
|
@@ -290,11 +300,11 @@ if __name__ == "__main__":
|
|
290
300
|
def run_client():
|
291
301
|
client = Monitor("127.0.0.1", 5555)
|
292
302
|
time.sleep(1) # Wait for server to start
|
293
|
-
|
303
|
+
|
294
304
|
client.set_column_names("index", "H", "S")
|
295
305
|
client.set_plots("(index,H);(index,S)")
|
296
306
|
client.roll()
|
297
|
-
|
307
|
+
|
298
308
|
for i in range(100):
|
299
309
|
client.add_point(i, np.random.randn(), np.sin(i / 20))
|
300
310
|
time.sleep(0.2)
|
qulab/monitor/ploter.py
CHANGED
@@ -6,18 +6,18 @@ data visualization. It includes features like auto-ranging, mouse interaction
|
|
6
6
|
for data selection, and clipboard integration.
|
7
7
|
"""
|
8
8
|
|
9
|
-
from .config import (COLOR_SELECTED, COLOR_UNSELECTED,
|
10
|
-
|
11
|
-
from .qt_compat import QtWidgets
|
9
|
+
from .config import (COLOR_SELECTED, COLOR_UNSELECTED, DEFAULT_COLORS,
|
10
|
+
LINE_WIDTHS, ROLL_INDICES, SYMBOL_SIZES)
|
11
|
+
from .qt_compat import QtWidgets # type: ignore
|
12
12
|
|
13
13
|
# the plotting widget
|
14
14
|
try:
|
15
|
-
import pyqtgraph as pg
|
15
|
+
import pyqtgraph as pg # type: ignore
|
16
16
|
except ImportError:
|
17
17
|
raise ImportError("Please install pyqtgraph first")
|
18
18
|
|
19
19
|
try:
|
20
|
-
import pyperclip as pc
|
20
|
+
import pyperclip as pc # type: ignore
|
21
21
|
HAS_CLIPBOARD = True
|
22
22
|
except ImportError:
|
23
23
|
HAS_CLIPBOARD = False
|
@@ -122,14 +122,16 @@ class PlotWidget(pg.PlotWidget):
|
|
122
122
|
def mousePressEvent(self, event):
|
123
123
|
"""Handle mouse press events for data selection."""
|
124
124
|
if event.button() == 4 and HAS_CLIPBOARD:
|
125
|
-
self.clip_pos_start = self.plotItem.vb.mapSceneToView(
|
125
|
+
self.clip_pos_start = self.plotItem.vb.mapSceneToView(
|
126
|
+
event.pos()).x()
|
126
127
|
else:
|
127
128
|
super().mousePressEvent(event)
|
128
129
|
|
129
130
|
def mouseReleaseEvent(self, event):
|
130
131
|
"""Handle mouse release events and copy selected data to clipboard."""
|
131
132
|
if event.button() == 4 and HAS_CLIPBOARD:
|
132
|
-
self.clip_pos_end = self.plotItem.vb.mapSceneToView(
|
133
|
+
self.clip_pos_end = self.plotItem.vb.mapSceneToView(
|
134
|
+
event.pos()).x()
|
133
135
|
if self.range_select:
|
134
136
|
pc.copy(f"{self.clip_pos_start},{self.clip_pos_end}")
|
135
137
|
else:
|
qulab/monitor/qt_compat.py
CHANGED
@@ -13,7 +13,8 @@ The module exports the following constants:
|
|
13
13
|
- TopDockWidgetArea: Top dock widget area constant
|
14
14
|
"""
|
15
15
|
|
16
|
-
from matplotlib.backends.qt_compat import QT_API, QtCore,
|
16
|
+
from matplotlib.backends.qt_compat import (QT_API, QtCore, # type: ignore
|
17
|
+
QtWidgets) # type: ignore
|
17
18
|
|
18
19
|
# Define Qt constants based on the Qt binding being used
|
19
20
|
if QT_API in ['PySide6', 'PyQt6']:
|
qulab/monitor/toolbar.py
CHANGED
@@ -14,7 +14,7 @@ import re
|
|
14
14
|
from typing import Callable, List, Tuple
|
15
15
|
|
16
16
|
from .config import STYLE, TRANSFORM_NAMES
|
17
|
-
from .qt_compat import AlignRight, QtWidgets
|
17
|
+
from .qt_compat import AlignRight, QtWidgets # type: ignore
|
18
18
|
|
19
19
|
|
20
20
|
def matched_xy_pairs(patterns: str, column_names: list[str]) -> list[tuple[str, str]]:
|
@@ -28,11 +28,11 @@ def matched_xy_pairs(patterns: str, column_names: list[str]) -> list[tuple[str,
|
|
28
28
|
Returns:
|
29
29
|
List of matched (x, y) column name pairs
|
30
30
|
"""
|
31
|
-
|
31
|
+
pattern_list = patterns.replace(" ", "").split(";")
|
32
32
|
pairs = []
|
33
33
|
for x, y in itertools.product(column_names, repeat=2):
|
34
34
|
test = f"{x},{y}"
|
35
|
-
for pattern in
|
35
|
+
for pattern in pattern_list:
|
36
36
|
r = re.match(pattern, test)
|
37
37
|
if r and r.group(0) == test:
|
38
38
|
pairs.append((x, y))
|
qulab/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "2.
|
1
|
+
__version__ = "2.12.0"
|
qulab/visualization/_autoplot.py
CHANGED
@@ -114,7 +114,7 @@ class MyLogFormatter(EngFormatter):
|
|
114
114
|
return super().format_eng(10.0**x)
|
115
115
|
|
116
116
|
|
117
|
-
def imshow_logx(x, y, z, x_unit=None, ax=None, **kwargs):
|
117
|
+
def imshow_logx(x, y, z, x_unit: str | None = None, ax=None, **kwargs):
|
118
118
|
if ax is None:
|
119
119
|
ax = plt.gca()
|
120
120
|
|
@@ -127,13 +127,13 @@ def imshow_logx(x, y, z, x_unit=None, ax=None, **kwargs):
|
|
127
127
|
img = ax.imshow(z, extent=extent, **kwargs)
|
128
128
|
|
129
129
|
ax.set_xticks(major_ticks, minor=False)
|
130
|
-
ax.xaxis.set_major_formatter(MyLogFormatter(x_unit))
|
130
|
+
ax.xaxis.set_major_formatter(MyLogFormatter(x_unit)) # type: ignore
|
131
131
|
ax.set_xticks(minor_ticks, minor=True)
|
132
132
|
|
133
133
|
return img
|
134
134
|
|
135
135
|
|
136
|
-
def imshow_logy(x, y, z, y_unit=None, ax=None, **kwargs):
|
136
|
+
def imshow_logy(x, y, z, y_unit: str | None = None, ax=None, **kwargs):
|
137
137
|
if ax is None:
|
138
138
|
ax = plt.gca()
|
139
139
|
|
@@ -146,13 +146,13 @@ def imshow_logy(x, y, z, y_unit=None, ax=None, **kwargs):
|
|
146
146
|
img = ax.imshow(z, extent=extent, **kwargs)
|
147
147
|
|
148
148
|
ax.set_yticks(major_ticks, minor=False)
|
149
|
-
ax.yaxis.set_major_formatter(MyLogFormatter(y_unit))
|
149
|
+
ax.yaxis.set_major_formatter(MyLogFormatter(y_unit)) # type: ignore
|
150
150
|
ax.set_yticks(minor_ticks, minor=True)
|
151
151
|
|
152
152
|
return img
|
153
153
|
|
154
154
|
|
155
|
-
def imshow_loglog(x, y, z, x_unit=None, y_unit=None, ax=None, **kwargs):
|
155
|
+
def imshow_loglog(x, y, z, x_unit: str | None = None, y_unit: str | None = None, ax=None, **kwargs):
|
156
156
|
if ax is None:
|
157
157
|
ax = plt.gca()
|
158
158
|
|
@@ -166,11 +166,11 @@ def imshow_loglog(x, y, z, x_unit=None, y_unit=None, ax=None, **kwargs):
|
|
166
166
|
img = ax.imshow(z, extent=extent, **kwargs)
|
167
167
|
|
168
168
|
ax.set_xticks(x_major_ticks, minor=False)
|
169
|
-
ax.xaxis.set_major_formatter(MyLogFormatter(x_unit))
|
169
|
+
ax.xaxis.set_major_formatter(MyLogFormatter(x_unit)) # type: ignore
|
170
170
|
ax.set_xticks(x_minor_ticks, minor=True)
|
171
171
|
|
172
172
|
ax.set_yticks(y_major_ticks, minor=False)
|
173
|
-
ax.yaxis.set_major_formatter(MyLogFormatter(y_unit))
|
173
|
+
ax.yaxis.set_major_formatter(MyLogFormatter(y_unit)) # type: ignore
|
174
174
|
ax.set_yticks(y_minor_ticks, minor=True)
|
175
175
|
|
176
176
|
return img
|
@@ -186,9 +186,9 @@ def plot_lines(x,
|
|
186
186
|
y_unit,
|
187
187
|
z_unit,
|
188
188
|
ax,
|
189
|
-
xscale='linear',
|
190
|
-
yscale='linear',
|
191
|
-
zscale='linear',
|
189
|
+
xscale: str = 'linear',
|
190
|
+
yscale: str = 'linear',
|
191
|
+
zscale: str = 'linear',
|
192
192
|
index=None,
|
193
193
|
**kwds):
|
194
194
|
z = np.asarray(z)
|
@@ -230,9 +230,9 @@ def plot_img(x,
|
|
230
230
|
z_unit,
|
231
231
|
fig,
|
232
232
|
ax,
|
233
|
-
xscale='linear',
|
234
|
-
yscale='linear',
|
235
|
-
zscale='linear',
|
233
|
+
xscale: str = 'linear',
|
234
|
+
yscale: str = 'linear',
|
235
|
+
zscale: str = 'linear',
|
236
236
|
resolution=None,
|
237
237
|
**kwds):
|
238
238
|
kwds.setdefault('origin', 'lower')
|
@@ -325,9 +325,9 @@ def plot_scatter(x,
|
|
325
325
|
z_unit,
|
326
326
|
fig,
|
327
327
|
ax,
|
328
|
-
xscale='linear',
|
329
|
-
yscale='linear',
|
330
|
-
zscale='linear',
|
328
|
+
xscale: str = 'linear',
|
329
|
+
yscale: str = 'linear',
|
330
|
+
zscale: str = 'linear',
|
331
331
|
**kwds):
|
332
332
|
if np.any(np.iscomplex(z)):
|
333
333
|
s = np.abs(z)
|
@@ -356,9 +356,9 @@ def autoplot(x,
|
|
356
356
|
fig=None,
|
357
357
|
ax=None,
|
358
358
|
index=None,
|
359
|
-
xscale='auto',
|
360
|
-
yscale='auto',
|
361
|
-
zscale='auto',
|
359
|
+
xscale: str = 'auto',
|
360
|
+
yscale: str = 'auto',
|
361
|
+
zscale: str = 'auto',
|
362
362
|
max_lines=3,
|
363
363
|
scatter_lim=1000,
|
364
364
|
resolution=None,
|
qulab/visualization/plot_circ.py
CHANGED
@@ -33,13 +33,13 @@ def make_path(fx, fy, dfx, dfy, t):
|
|
33
33
|
|
34
34
|
|
35
35
|
def plot_square(ax,
|
36
|
-
x=0,
|
37
|
-
y=0,
|
38
|
-
width=1,
|
39
|
-
hight=1,
|
36
|
+
x=0.0,
|
37
|
+
y=0.0,
|
38
|
+
width=1.0,
|
39
|
+
hight=1.0,
|
40
40
|
radius=0.2,
|
41
41
|
ls='-',
|
42
|
-
lw=2,
|
42
|
+
lw=2.0,
|
43
43
|
fc='none',
|
44
44
|
ec='black'):
|
45
45
|
r = radius
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import functools
|
2
2
|
import operator
|
3
|
+
from typing import cast
|
3
4
|
|
4
5
|
import matplotlib.pyplot as plt
|
5
6
|
import numpy as np
|
@@ -53,6 +54,85 @@ def complete_layout(layout):
|
|
53
54
|
return layout
|
54
55
|
|
55
56
|
|
57
|
+
def read_xlsx_to_dict(filepath: str,
|
58
|
+
key_col: int = 0,
|
59
|
+
value_col: int = 4,
|
60
|
+
sheet_name: str = 0) -> dict:
|
61
|
+
"""
|
62
|
+
读取 .xlsx 文件,将第 key_col 列和第 value_col 列的值分别作为 key、value,返回一个字典。
|
63
|
+
|
64
|
+
:param filepath: Excel 文件路径
|
65
|
+
:param key_col: 用作字典键的列索引(0 表示第一列)
|
66
|
+
:param value_col: 用作字典值的列索引(0 表示第一列)
|
67
|
+
:param sheet_name: 要读取的 sheet 名称或索引,默认第一个 sheet
|
68
|
+
:return: { key: value, ... } 形式的字典
|
69
|
+
"""
|
70
|
+
import pandas as pd
|
71
|
+
|
72
|
+
# 读取整个表格
|
73
|
+
# df = pd.read_excel(filepath, sheet_name=sheet_name, header=None)
|
74
|
+
df = pd.read_excel(filepath, sheet_name=sheet_name)
|
75
|
+
|
76
|
+
# 提取指定列,生成键值对并返回字典
|
77
|
+
keys = df.iloc[:, key_col]
|
78
|
+
values = df.iloc[:, value_col]
|
79
|
+
return dict(zip(keys, values))
|
80
|
+
|
81
|
+
|
82
|
+
def load_layout_from_xlsx(qubit_info, coupler_info, pad_info):
|
83
|
+
"""
|
84
|
+
从 .xlsx 文件中加载布局信息。
|
85
|
+
|
86
|
+
:param qubit_info: 量子比特信息文件路径
|
87
|
+
:param coupler_info: 耦合器信息文件路径
|
88
|
+
:param pad_info: 垫片信息文件路径
|
89
|
+
:return: 布局信息
|
90
|
+
"""
|
91
|
+
import pandas as pd
|
92
|
+
|
93
|
+
_qubits = {}
|
94
|
+
|
95
|
+
qubit_pad = read_xlsx_to_dict(qubit_info, value_col=4)
|
96
|
+
coupler_pad = read_xlsx_to_dict(coupler_info, value_col=3)
|
97
|
+
pads = {
|
98
|
+
v: k
|
99
|
+
for k, v in qubit_pad.items()
|
100
|
+
} | {
|
101
|
+
v: k
|
102
|
+
for k, v in coupler_pad.items()
|
103
|
+
}
|
104
|
+
pad_info = read_xlsx_to_dict(pad_info, value_col=2)
|
105
|
+
|
106
|
+
lyt = {'qubits': {}, 'couplers': {}, 'feedlines': {}}
|
107
|
+
|
108
|
+
for pad, script in pad_info.items():
|
109
|
+
info = eval(script)
|
110
|
+
match info['style']:
|
111
|
+
case 'Q':
|
112
|
+
qubit = pads[pad]
|
113
|
+
lyt['qubits'][qubit] = {'pos': info['qb'], 'pad': pad}
|
114
|
+
_qubits[info['qb']] = qubit
|
115
|
+
case 'C':
|
116
|
+
coupler = pads[pad]
|
117
|
+
if 'cpl' in info:
|
118
|
+
pos = tuple(info['cpl'])
|
119
|
+
else:
|
120
|
+
pos = tuple(info['qb'])
|
121
|
+
lyt['couplers'][coupler] = {'qubits': pos, 'pad': pad}
|
122
|
+
case 'TL':
|
123
|
+
l = info['tl']
|
124
|
+
if f"T{l}" in lyt['feedlines']:
|
125
|
+
lyt['feedlines'][f"T{l}"]['pads'].append(pad)
|
126
|
+
else:
|
127
|
+
lyt['feedlines'][f"T{l}"] = {'pads': [pad]}
|
128
|
+
|
129
|
+
for coupler in lyt['couplers']:
|
130
|
+
qubits = lyt['couplers'][coupler]['qubits']
|
131
|
+
lyt['couplers'][coupler]['qubits'] = [_qubits[p] for p in qubits]
|
132
|
+
|
133
|
+
return complete_layout(lyt)
|
134
|
+
|
135
|
+
|
56
136
|
def get_shared_coupler(layout, q1, q2):
|
57
137
|
for c in layout['qubits'][q1]['couplers']:
|
58
138
|
if q2 in layout['couplers'][c]['qubits']:
|
@@ -245,6 +325,10 @@ def _draw_coupler(ax, coupler, layout, q1, q2, pos1, pos2):
|
|
245
325
|
|
246
326
|
text_rotation = 180 * np.arctan2(pos2[1] - pos1[1],
|
247
327
|
pos2[0] - pos1[0]) / np.pi
|
328
|
+
if text_rotation > 90:
|
329
|
+
text_rotation -= 180
|
330
|
+
elif text_rotation < -90:
|
331
|
+
text_rotation += 180
|
248
332
|
|
249
333
|
path = circle_link_path(pos1, pos2, r1, r2, width)
|
250
334
|
plot_range(ax,
|
@@ -452,15 +536,19 @@ def fill_layout(layout,
|
|
452
536
|
coupler_cmap = plt.get_cmap(coupler_cmap)
|
453
537
|
|
454
538
|
if qubit_norm is None:
|
455
|
-
qubit_norm =
|
456
|
-
|
457
|
-
|
458
|
-
|
539
|
+
qubit_norm = cast(
|
540
|
+
Normalize,
|
541
|
+
get_norm(params,
|
542
|
+
layout['qubits'].keys(),
|
543
|
+
vmin=qubit_vmin,
|
544
|
+
vmax=qubit_vmax))
|
459
545
|
if coupler_norm is None:
|
460
|
-
coupler_norm =
|
461
|
-
|
462
|
-
|
463
|
-
|
546
|
+
coupler_norm = cast(
|
547
|
+
Normalize,
|
548
|
+
get_norm(params,
|
549
|
+
layout['couplers'].keys(),
|
550
|
+
vmin=coupler_vmin,
|
551
|
+
vmax=coupler_vmax))
|
464
552
|
layout['__colorbar__'] = {
|
465
553
|
'coupler': {
|
466
554
|
'cmap': coupler_cmap,
|
@@ -1,8 +1,8 @@
|
|
1
|
-
qulab/__init__.py,sha256=
|
1
|
+
qulab/__init__.py,sha256=ijh3NWuSCU_KWRrPfddX4vfPcYPmvKs64vSTl9qd-SU,2178
|
2
2
|
qulab/__main__.py,sha256=fjaRSL_uUjNIzBGNgjlGswb9TJ2VD5qnkZHW3hItrD4,68
|
3
3
|
qulab/typing.py,sha256=vg62sGqxuD9CI5677ejlzAmf2fVdAESZCQjAE_xSxPg,69
|
4
4
|
qulab/utils.py,sha256=B_8QdY9OMY7WU-F200v93BDJXJpQcKAHihnOXeEvv_w,3966
|
5
|
-
qulab/version.py,sha256=
|
5
|
+
qulab/version.py,sha256=9qeMwbCMEAjH-vk_63Tak43katUwSOLexvq8N_IKi8c,22
|
6
6
|
qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
qulab/cli/commands.py,sha256=ywKmwbGNBCVASx8OsgrRttaLz9ogwY38ZdKj7I-tdJ4,813
|
8
8
|
qulab/cli/config.py,sha256=Z-lePcDMeeQmwFpdfQHqZuaXTPhWUHN5KrlSqrya73Y,6324
|
@@ -11,21 +11,21 @@ qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,10
|
|
11
11
|
qulab/executor/analyze.py,sha256=VYTfiOYJe5gDbtGA4wOkrQhhu55iIrRVByx-gBLUUm4,5672
|
12
12
|
qulab/executor/cli.py,sha256=fTB7V8xNCvpU8EMa__ysBvRCzruP-QFbXOyLpeTPx0E,25711
|
13
13
|
qulab/executor/load.py,sha256=eMlzOrrn8GpbP3J3uY5JJ8iO7tL5B1DWP1z2qiGyNhU,20385
|
14
|
-
qulab/executor/registry.py,sha256=
|
14
|
+
qulab/executor/registry.py,sha256=yWO6nJ1nMVve_HF5xzSd7QmZEIjoGvD_Txg73_f30gE,9279
|
15
15
|
qulab/executor/schedule.py,sha256=cDFM_tIMvxHLxb-tBA6fEPF9u-4LcgnQDxbaquZIQKc,21727
|
16
16
|
qulab/executor/storage.py,sha256=8K73KGLAVgchJdtd4rKHXkr1CQOJORWH-Gi57w8IYsw,21081
|
17
|
-
qulab/executor/template.py,sha256=
|
17
|
+
qulab/executor/template.py,sha256=XyZKt2b0J-gSEA9mHoWmA7ADLWrUwOAL5oxYkX-UNg8,10837
|
18
18
|
qulab/executor/utils.py,sha256=YSUEYjyYTJTjiJmd-l5GTEnSyD6bqEdNoWhivEAfGZA,7112
|
19
19
|
qulab/monitor/__init__.py,sha256=FNYMIUr8ycRM4XmsAGpRK-A-SQsJZlcRWghXcGTgAi0,44
|
20
20
|
qulab/monitor/__main__.py,sha256=Txy4d7vgVYUWwiHxX3uwtsi1ewde-MaiSC_K0ePoPiM,1372
|
21
21
|
qulab/monitor/config.py,sha256=lMMRHy6wnVgMHiRMQqev5lj8mbF2g29TLrK82dwp_2k,1950
|
22
|
-
qulab/monitor/dataset.py,sha256=
|
23
|
-
qulab/monitor/event_queue.py,sha256=
|
24
|
-
qulab/monitor/mainwindow.py,sha256=
|
25
|
-
qulab/monitor/monitor.py,sha256=
|
26
|
-
qulab/monitor/ploter.py,sha256=
|
27
|
-
qulab/monitor/qt_compat.py,sha256=
|
28
|
-
qulab/monitor/toolbar.py,sha256=
|
22
|
+
qulab/monitor/dataset.py,sha256=q9ex0MnC0k-_h1dMFDXZWLERCjM2xPqEc-Obt4AsVZQ,6232
|
23
|
+
qulab/monitor/event_queue.py,sha256=Pp9MQ5NtOHBxohHNjv9YfXI1H4T-eDshv3AhjOKp7tE,4501
|
24
|
+
qulab/monitor/mainwindow.py,sha256=sGrSDUUZv0ilaw-T-7h4fa-TtmDluMsLNRnUADKgEQE,10043
|
25
|
+
qulab/monitor/monitor.py,sha256=3vJeMRKtlDwQHsOz7cZlbNNAQbaCoKRFCgLxri5dtpo,9814
|
26
|
+
qulab/monitor/ploter.py,sha256=cPyc1TyHHoKsaCbzIDHMUVwjKqPZLjjvBQb-fm8VKaw,4882
|
27
|
+
qulab/monitor/qt_compat.py,sha256=vbblAzlw4pKo-F9yPZt4DOc-KdsSBucud1F8jv00G18,1730
|
28
|
+
qulab/monitor/toolbar.py,sha256=A4UtLCnBWyk_JZ16u66dmcoTwY6-Cg4h6QQEEp3Ub-0,10363
|
29
29
|
qulab/scan/__init__.py,sha256=Z88CzGsvr1VdKbF6aYgQv3j-fsEkKmqvpvX4LlzOM98,87
|
30
30
|
qulab/scan/curd.py,sha256=tiJ0oo2DqirK2fpAAAA-6OFAjAuKG5W21nLqfLvTLyQ,6895
|
31
31
|
qulab/scan/models.py,sha256=JFofv-RH0gpS3--M6izXiQg7iGkS9a_em2DwhS5kTTk,17626
|
@@ -89,16 +89,16 @@ qulab/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
89
|
qulab/tools/connection_helper.py,sha256=o1t6UpJQPyj4mWY66axgQkgsqUzdkhEGBJo44x9U1iE,946
|
90
90
|
qulab/visualization/__init__.py,sha256=26cuHt3QIJXUb3VaMxlJx3IQTOUVJFKlYBZr7WMP53M,6129
|
91
91
|
qulab/visualization/__main__.py,sha256=9zKK3yZFy0leU40ou6BpRC1Fsetfc1gjjFzIZYIwP6Y,1639
|
92
|
-
qulab/visualization/_autoplot.py,sha256=
|
93
|
-
qulab/visualization/plot_circ.py,sha256=
|
94
|
-
qulab/visualization/plot_layout.py,sha256=
|
92
|
+
qulab/visualization/_autoplot.py,sha256=2ECb2USU3_MSwo2d8qzMMO4DK9OU1bA6RYr7FCss1D0,14369
|
93
|
+
qulab/visualization/plot_circ.py,sha256=Lxi-Nnik9MBtsNur0iyp9DTdy_IMALRsHBg2hZbPkGc,8769
|
94
|
+
qulab/visualization/plot_layout.py,sha256=Q8yOGYQ-oOle1W7cN4am9ABI8T-Xtk3W6BEX5bFSeWg,20464
|
95
95
|
qulab/visualization/plot_seq.py,sha256=UWTS6p9nfX_7B8ehcYo6UnSTUCjkBsNU9jiOeW2calY,6751
|
96
96
|
qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
|
97
97
|
qulab/visualization/rot3d.py,sha256=CuLfG1jw1032HNNZxzC0OWtNzKsbj2e2WRYhMWDgvMQ,1321
|
98
98
|
qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
|
99
|
-
qulab-2.
|
100
|
-
qulab-2.
|
101
|
-
qulab-2.
|
102
|
-
qulab-2.
|
103
|
-
qulab-2.
|
104
|
-
qulab-2.
|
99
|
+
qulab-2.12.0.dist-info/licenses/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
|
100
|
+
qulab-2.12.0.dist-info/METADATA,sha256=ciOrjSwiDMrPsQizRcfSzDphr_TCmgrDFjx3Njx6qto,3944
|
101
|
+
qulab-2.12.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
102
|
+
qulab-2.12.0.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
|
103
|
+
qulab-2.12.0.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
|
104
|
+
qulab-2.12.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|