QuLab 2.5.2__cp312-cp312-macosx_10_13_universal2.whl → 2.5.4__cp312-cp312-macosx_10_13_universal2.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-2.5.2.dist-info → QuLab-2.5.4.dist-info}/METADATA +1 -1
- {QuLab-2.5.2.dist-info → QuLab-2.5.4.dist-info}/RECORD +12 -12
- qulab/executor/cli.py +34 -6
- qulab/executor/load.py +62 -10
- qulab/executor/schedule.py +8 -0
- qulab/executor/utils.py +7 -5
- qulab/fun.cpython-312-darwin.so +0 -0
- qulab/version.py +1 -1
- {QuLab-2.5.2.dist-info → QuLab-2.5.4.dist-info}/LICENSE +0 -0
- {QuLab-2.5.2.dist-info → QuLab-2.5.4.dist-info}/WHEEL +0 -0
- {QuLab-2.5.2.dist-info → QuLab-2.5.4.dist-info}/entry_points.txt +0 -0
- {QuLab-2.5.2.dist-info → QuLab-2.5.4.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
qulab/__init__.py,sha256=XnSePkDDgfbmEpu5uXK6spygxaqVt9emMubHYKIjSwc,244
|
|
2
2
|
qulab/__main__.py,sha256=fjaRSL_uUjNIzBGNgjlGswb9TJ2VD5qnkZHW3hItrD4,68
|
|
3
3
|
qulab/dicttree.py,sha256=tRRMpGZYVOLw0TEByE3_2Ss8FdOmzuGL9e1DWbs8qoY,13684
|
|
4
|
-
qulab/fun.cpython-312-darwin.so,sha256=
|
|
4
|
+
qulab/fun.cpython-312-darwin.so,sha256=Xy5kG_e3ih1w_mhSG3jDBLzIaN53MgKXEsXfXA6T6ec,126864
|
|
5
5
|
qulab/typing.py,sha256=5xCLfrp1aZpKpDy4p2arbFszw2eK3hGUjZa-XSvC_-8,69
|
|
6
|
-
qulab/version.py,sha256=
|
|
6
|
+
qulab/version.py,sha256=kUk6VjaCueGXZEsY69h4VouFnQXNOenbPlluQV766gk,21
|
|
7
7
|
qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
qulab/cli/commands.py,sha256=tgDIkkeIoasQXAifJZ6NU8jDgpNgb2a-B0C4nF0evrE,559
|
|
9
9
|
qulab/cli/config.py,sha256=SdNmWzweWAdyk8M2oKYhMxnkaJ0qIayPlsLGCNlVqME,3108
|
|
10
10
|
qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,101
|
|
11
|
-
qulab/executor/cli.py,sha256=
|
|
12
|
-
qulab/executor/load.py,sha256=
|
|
13
|
-
qulab/executor/schedule.py,sha256=
|
|
11
|
+
qulab/executor/cli.py,sha256=ZGnQdUFZmU812gsnqbKhaJzwWLdoPt42CukPbZ7Yv8k,6684
|
|
12
|
+
qulab/executor/load.py,sha256=M4_CfWU65y5wXTNSaaJFp9Plui0wOtxPF181prD-HVU,14345
|
|
13
|
+
qulab/executor/schedule.py,sha256=SeeP3QwABoa8KWee_5QMwaSSjv6VwbRpDVTF1pHRnR0,12367
|
|
14
14
|
qulab/executor/storage.py,sha256=s1xrI4bPTnyM4Nj0CkPxr3NdmnSp18LKnwm-ZoxR-Q0,7191
|
|
15
15
|
qulab/executor/transform.py,sha256=AazWdlkEoOBaUJpTYsT5J4f0RanzCEeo-ThwEg8BB4Y,1262
|
|
16
|
-
qulab/executor/utils.py,sha256=
|
|
16
|
+
qulab/executor/utils.py,sha256=VZ_VPYT2MFIfrCtfEW1I7T4NKFIbOvfVac8Sv377MTY,4221
|
|
17
17
|
qulab/monitor/__init__.py,sha256=nTHelnDpxRS_fl_B38TsN0njgq8eVTEz9IAnN3NbDlM,42
|
|
18
18
|
qulab/monitor/__main__.py,sha256=w3yUcqq195LzSnXTkQcuC1RSFRhy4oQ_PEBmucXguME,97
|
|
19
19
|
qulab/monitor/config.py,sha256=fQ5JcsMApKc1UwANEnIvbDQZl8uYW0tle92SaYtX9lI,744
|
|
@@ -93,9 +93,9 @@ qulab/visualization/plot_seq.py,sha256=UWTS6p9nfX_7B8ehcYo6UnSTUCjkBsNU9jiOeW2ca
|
|
|
93
93
|
qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
|
|
94
94
|
qulab/visualization/rot3d.py,sha256=lMrEJlRLwYe6NMBlGkKYpp_V9CTipOAuDy6QW_cQK00,734
|
|
95
95
|
qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
|
|
96
|
-
QuLab-2.5.
|
|
97
|
-
QuLab-2.5.
|
|
98
|
-
QuLab-2.5.
|
|
99
|
-
QuLab-2.5.
|
|
100
|
-
QuLab-2.5.
|
|
101
|
-
QuLab-2.5.
|
|
96
|
+
QuLab-2.5.4.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
|
|
97
|
+
QuLab-2.5.4.dist-info/METADATA,sha256=TwwWVTHbmI2g3NKVmVe_gpJG-w5WgzzynlzzXe4yjBU,3698
|
|
98
|
+
QuLab-2.5.4.dist-info/WHEEL,sha256=iDXcyuxg-66TzzqHGH-kgw_HJdaJE_1RHznrvPNCSNs,115
|
|
99
|
+
QuLab-2.5.4.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
|
|
100
|
+
QuLab-2.5.4.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
|
|
101
|
+
QuLab-2.5.4.dist-info/RECORD,,
|
qulab/executor/cli.py
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
import functools
|
|
2
|
+
import graphlib
|
|
2
3
|
import importlib
|
|
3
4
|
import os
|
|
4
|
-
import sys
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
from loguru import logger
|
|
9
9
|
|
|
10
|
-
from ..cli.config import
|
|
11
|
-
from .load import find_unreferenced_workflows, get_entries,
|
|
10
|
+
from ..cli.config import get_config_value, log_options
|
|
11
|
+
from .load import (WorkflowType, find_unreferenced_workflows, get_entries,
|
|
12
|
+
load_workflow, make_graph)
|
|
12
13
|
from .schedule import maintain as maintain_workflow
|
|
13
14
|
from .schedule import run as run_workflow
|
|
14
15
|
from .transform import set_config_api
|
|
15
16
|
from .utils import workflow_template
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
@logger.catch(reraise=True)
|
|
20
|
+
def check_toplogy(workflow: WorkflowType, code_path: str | Path) -> dict:
|
|
21
|
+
graph = {}
|
|
22
|
+
try:
|
|
23
|
+
graphlib.TopologicalSorter(make_graph(workflow, graph,
|
|
24
|
+
code_path)).static_order()
|
|
25
|
+
except graphlib.CycleError as e:
|
|
26
|
+
logger.error(
|
|
27
|
+
f"Workflow {workflow.__workflow_id__} has a circular dependency: {e}"
|
|
28
|
+
)
|
|
29
|
+
raise e
|
|
30
|
+
return graph
|
|
31
|
+
|
|
32
|
+
|
|
18
33
|
def command_option(command_name):
|
|
19
34
|
"""命令专属配置装饰器工厂"""
|
|
20
35
|
|
|
@@ -68,7 +83,7 @@ def create(workflow, code):
|
|
|
68
83
|
deps = find_unreferenced_workflows(code)
|
|
69
84
|
|
|
70
85
|
with open(fname, 'w') as f:
|
|
71
|
-
f.write(workflow_template(list(deps)))
|
|
86
|
+
f.write(workflow_template(workflow, list(deps)))
|
|
72
87
|
click.echo(f'{workflow} created')
|
|
73
88
|
|
|
74
89
|
|
|
@@ -142,6 +157,7 @@ def run(workflow, code, data, api, plot, no_dependents, update):
|
|
|
142
157
|
data = Path(os.path.expanduser(data))
|
|
143
158
|
|
|
144
159
|
wf = load_workflow(workflow, code)
|
|
160
|
+
check_toplogy(wf, code)
|
|
145
161
|
|
|
146
162
|
if no_dependents:
|
|
147
163
|
if hasattr(wf, 'entries'):
|
|
@@ -152,9 +168,19 @@ def run(workflow, code, data, api, plot, no_dependents, update):
|
|
|
152
168
|
else:
|
|
153
169
|
if hasattr(wf, 'entries'):
|
|
154
170
|
for entry in get_entries(wf, code):
|
|
155
|
-
maintain_workflow(entry,
|
|
171
|
+
maintain_workflow(entry,
|
|
172
|
+
code,
|
|
173
|
+
data,
|
|
174
|
+
run=True,
|
|
175
|
+
plot=plot,
|
|
176
|
+
update=update)
|
|
156
177
|
else:
|
|
157
|
-
maintain_workflow(wf,
|
|
178
|
+
maintain_workflow(wf,
|
|
179
|
+
code,
|
|
180
|
+
data,
|
|
181
|
+
run=True,
|
|
182
|
+
plot=plot,
|
|
183
|
+
update=update)
|
|
158
184
|
|
|
159
185
|
|
|
160
186
|
@click.command()
|
|
@@ -181,6 +207,8 @@ def maintain(workflow, code, data, api, plot):
|
|
|
181
207
|
data = Path(os.path.expanduser(data))
|
|
182
208
|
|
|
183
209
|
wf = load_workflow(workflow, code)
|
|
210
|
+
check_toplogy(wf, code)
|
|
211
|
+
|
|
184
212
|
if hasattr(wf, 'entries'):
|
|
185
213
|
for entry in get_entries(wf, code):
|
|
186
214
|
maintain_workflow(entry, code, data, run=False, plot=plot)
|
qulab/executor/load.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import base64
|
|
2
|
+
import graphlib
|
|
2
3
|
import hashlib
|
|
3
4
|
import inspect
|
|
4
5
|
import lzma
|
|
@@ -259,7 +260,7 @@ def load_workflow_from_template(template_path: str,
|
|
|
259
260
|
with open(base_path / path) as f:
|
|
260
261
|
content = f.read()
|
|
261
262
|
|
|
262
|
-
mtime = max(
|
|
263
|
+
mtime = max((base_path / template_path).stat().st_mtime, mtime)
|
|
263
264
|
hash_str, mapping_code = encode_mapping(mapping)
|
|
264
265
|
|
|
265
266
|
def replace(text):
|
|
@@ -354,14 +355,65 @@ def load_workflow(workflow: str | tuple[str, dict],
|
|
|
354
355
|
|
|
355
356
|
def get_dependents(workflow: WorkflowType,
|
|
356
357
|
code_path: str | Path) -> list[WorkflowType]:
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
358
|
+
if callable(getattr(workflow, 'depends', None)):
|
|
359
|
+
if not can_call_without_args(workflow.depends):
|
|
360
|
+
raise AttributeError(
|
|
361
|
+
f'Workflow {workflow.__workflow_id__} "depends" function should not have any parameters'
|
|
362
|
+
)
|
|
363
|
+
return [
|
|
364
|
+
load_workflow(n, code_path, mtime=workflow.__mtime__)
|
|
365
|
+
for n in workflow.depends()
|
|
366
|
+
]
|
|
367
|
+
elif isinstance(getattr(workflow, 'depends', None), (list, tuple)):
|
|
368
|
+
return [
|
|
369
|
+
load_workflow(n, code_path, mtime=workflow.__mtime__)
|
|
370
|
+
for n in workflow.depends
|
|
371
|
+
]
|
|
372
|
+
elif getattr(workflow, 'entries', None) is None:
|
|
373
|
+
return []
|
|
374
|
+
else:
|
|
375
|
+
raise AttributeError(
|
|
376
|
+
f'Workflow {workflow.__workflow_id__} "depends" should be a callable or a list'
|
|
377
|
+
)
|
|
361
378
|
|
|
362
379
|
|
|
363
|
-
def get_entries(workflow: WorkflowType,
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
380
|
+
def get_entries(workflow: WorkflowType,
|
|
381
|
+
code_path: str | Path) -> list[WorkflowType]:
|
|
382
|
+
if callable(getattr(workflow, 'entries', None)):
|
|
383
|
+
if not can_call_without_args(workflow.entries):
|
|
384
|
+
raise AttributeError(
|
|
385
|
+
f'Workflow {workflow.__workflow_id__} "entries" function should not have any parameters'
|
|
386
|
+
)
|
|
387
|
+
return [
|
|
388
|
+
load_workflow(n, code_path, mtime=workflow.__mtime__)
|
|
389
|
+
for n in workflow.entries()
|
|
390
|
+
]
|
|
391
|
+
elif isinstance(getattr(workflow, 'entries', None), (list, tuple)):
|
|
392
|
+
return [
|
|
393
|
+
load_workflow(n, code_path, mtime=workflow.__mtime__)
|
|
394
|
+
for n in workflow.entries
|
|
395
|
+
]
|
|
396
|
+
elif getattr(workflow, 'entries', None) is None:
|
|
397
|
+
return []
|
|
398
|
+
else:
|
|
399
|
+
raise AttributeError(
|
|
400
|
+
f'Workflow {workflow.__workflow_id__} "entries" should be a callable or a list'
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def make_graph(workflow: WorkflowType, graph: dict, code_path: str | Path):
|
|
405
|
+
if workflow.__workflow_id__ in graph:
|
|
406
|
+
raise graphlib.CycleError(
|
|
407
|
+
f"Workflow {workflow.__workflow_id__} has a circular dependency")
|
|
408
|
+
graph[workflow.__workflow_id__] = []
|
|
409
|
+
|
|
410
|
+
if hasattr(workflow, 'entries'):
|
|
411
|
+
for w in get_entries(workflow, code_path):
|
|
412
|
+
graph[workflow.__workflow_id__].append(w.__workflow_id__)
|
|
413
|
+
make_graph(w, graph=graph, code_path=code_path)
|
|
414
|
+
elif hasattr(workflow, 'depends'):
|
|
415
|
+
for w in get_dependents(workflow, code_path):
|
|
416
|
+
graph[workflow.__workflow_id__].append(w.__workflow_id__)
|
|
417
|
+
make_graph(w, graph=graph, code_path=code_path)
|
|
418
|
+
|
|
419
|
+
return graph
|
qulab/executor/schedule.py
CHANGED
|
@@ -73,9 +73,17 @@ def call_analyzer(node,
|
|
|
73
73
|
plot=False) -> Result:
|
|
74
74
|
if check:
|
|
75
75
|
result = node.check_analyze(result, history=history)
|
|
76
|
+
if not isinstance(result, Result):
|
|
77
|
+
raise TypeError(
|
|
78
|
+
f'"{node.__workflow_id__}" : "check_analyze" must return a Result object'
|
|
79
|
+
)
|
|
76
80
|
result.fully_calibrated = False
|
|
77
81
|
else:
|
|
78
82
|
result = node.analyze(result, history=history)
|
|
83
|
+
if not isinstance(result, Result):
|
|
84
|
+
raise TypeError(
|
|
85
|
+
f'"{node.__workflow_id__}" : "analyze" must return a Result object'
|
|
86
|
+
)
|
|
79
87
|
result.fully_calibrated = True
|
|
80
88
|
if plot:
|
|
81
89
|
call_plot(node, result)
|
qulab/executor/utils.py
CHANGED
|
@@ -30,7 +30,7 @@ def dependent_tree(node: str, code_path: str | Path) -> dict[str, list[str]]:
|
|
|
30
30
|
return tree
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def workflow_template(deps: list[str]) -> str:
|
|
33
|
+
def workflow_template(workflow: str, deps: list[str]) -> str:
|
|
34
34
|
return f"""def VAR(s): pass # 没有实际作用,只是用来抑制编辑器的警告。
|
|
35
35
|
|
|
36
36
|
import numpy as np
|
|
@@ -47,7 +47,7 @@ def depends():
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def calibrate():
|
|
50
|
-
logger.info(f"
|
|
50
|
+
logger.info(f"running {workflow} ...")
|
|
51
51
|
|
|
52
52
|
# calibrate 是一个完整的校准实验,如power Rabi,Ramsey等。
|
|
53
53
|
# 你需要足够的扫描点,以使得后续的 analyze 可以拟合出合适的参数。
|
|
@@ -58,10 +58,11 @@ def calibrate():
|
|
|
58
58
|
for i in x:
|
|
59
59
|
y.append(np.sin(i))
|
|
60
60
|
|
|
61
|
+
logger.info(f"running {workflow} ... finished!")
|
|
61
62
|
return x, y
|
|
62
63
|
|
|
63
64
|
|
|
64
|
-
def analyze(result: Result, history: Result | None) -> Result:
|
|
65
|
+
def analyze(result: Result, history: Result | None = None) -> Result:
|
|
65
66
|
\"\"\"
|
|
66
67
|
分析校准结果。
|
|
67
68
|
|
|
@@ -93,7 +94,7 @@ def analyze(result: Result, history: Result | None) -> Result:
|
|
|
93
94
|
|
|
94
95
|
|
|
95
96
|
def check():
|
|
96
|
-
logger.info(f"
|
|
97
|
+
logger.info(f"checking {workflow} ...")
|
|
97
98
|
|
|
98
99
|
# check 是一个快速检查实验,用于检查校准是否过时。
|
|
99
100
|
# 你只需要少数扫描点,让后续的 check_analyze 知道参数是否漂移,数据
|
|
@@ -105,10 +106,11 @@ def check():
|
|
|
105
106
|
for i in x:
|
|
106
107
|
y.append(np.sin(i))
|
|
107
108
|
|
|
109
|
+
logger.info(f"checking {workflow} ... finished!")
|
|
108
110
|
return x, y
|
|
109
111
|
|
|
110
112
|
|
|
111
|
-
def check_analyze(result: Result, history: Result) -> Result:
|
|
113
|
+
def check_analyze(result: Result, history: Result | None = None) -> Result:
|
|
112
114
|
\"\"\"
|
|
113
115
|
分析检查结果。
|
|
114
116
|
|
qulab/fun.cpython-312-darwin.so
CHANGED
|
Binary file
|
qulab/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.5.
|
|
1
|
+
__version__ = "2.5.4"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|