QuLab 2.7.6__cp310-cp310-macosx_10_9_universal2.whl → 2.7.10__cp310-cp310-macosx_10_9_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.7.6.dist-info → QuLab-2.7.10.dist-info}/METADATA +1 -1
- {QuLab-2.7.6.dist-info → QuLab-2.7.10.dist-info}/RECORD +16 -16
- qulab/__init__.py +2 -2
- qulab/executor/cli.py +2 -2
- qulab/executor/load.py +11 -11
- qulab/executor/schedule.py +205 -168
- qulab/executor/storage.py +93 -77
- qulab/executor/transform.py +8 -8
- qulab/executor/utils.py +33 -33
- qulab/fun.cpython-310-darwin.so +0 -0
- qulab/typing.py +1 -1
- qulab/version.py +1 -1
- {QuLab-2.7.6.dist-info → QuLab-2.7.10.dist-info}/LICENSE +0 -0
- {QuLab-2.7.6.dist-info → QuLab-2.7.10.dist-info}/WHEEL +0 -0
- {QuLab-2.7.6.dist-info → QuLab-2.7.10.dist-info}/entry_points.txt +0 -0
- {QuLab-2.7.6.dist-info → QuLab-2.7.10.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,20 @@
|
|
1
|
-
qulab/__init__.py,sha256=
|
1
|
+
qulab/__init__.py,sha256=KJcUcZ5qXY6wlAoirzK_B-dgtDjsLmOE671v3gcXO_c,286
|
2
2
|
qulab/__main__.py,sha256=fjaRSL_uUjNIzBGNgjlGswb9TJ2VD5qnkZHW3hItrD4,68
|
3
3
|
qulab/dicttree.py,sha256=tRRMpGZYVOLw0TEByE3_2Ss8FdOmzuGL9e1DWbs8qoY,13684
|
4
|
-
qulab/fun.cpython-310-darwin.so,sha256=
|
5
|
-
qulab/typing.py,sha256=
|
4
|
+
qulab/fun.cpython-310-darwin.so,sha256=onm3XhLaPD33T04UQ2QP32Gkl2E9xWjH45aY_Aqwjc0,126864
|
5
|
+
qulab/typing.py,sha256=vg62sGqxuD9CI5677ejlzAmf2fVdAESZCQjAE_xSxPg,69
|
6
6
|
qulab/utils.py,sha256=JIXMSmZU0uYfKG_tzawpK7vRNPRir_hJE8JlqkVLX2o,1260
|
7
|
-
qulab/version.py,sha256=
|
7
|
+
qulab/version.py,sha256=jdPSCkDOwzHQzdidl89buWuyX5dorFZluLWAvXtMdIU,22
|
8
8
|
qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
qulab/cli/commands.py,sha256=tgDIkkeIoasQXAifJZ6NU8jDgpNgb2a-B0C4nF0evrE,559
|
10
10
|
qulab/cli/config.py,sha256=SdNmWzweWAdyk8M2oKYhMxnkaJ0qIayPlsLGCNlVqME,3108
|
11
11
|
qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,101
|
12
|
-
qulab/executor/cli.py,sha256=
|
13
|
-
qulab/executor/load.py,sha256=
|
14
|
-
qulab/executor/schedule.py,sha256=
|
15
|
-
qulab/executor/storage.py,sha256=
|
16
|
-
qulab/executor/transform.py,sha256=
|
17
|
-
qulab/executor/utils.py,sha256=
|
12
|
+
qulab/executor/cli.py,sha256=gGka2M6xccfM8facsIJ2qZ1y2Yx8C4BRhc1JG6nK9mo,8932
|
13
|
+
qulab/executor/load.py,sha256=4FY_SwumLDUewC265v4j_ZGGpfYOgH4c8PtglYcWpBw,18077
|
14
|
+
qulab/executor/schedule.py,sha256=S8zRdkM2_I9-EqMUCEGI9boe3sfc68Gn5NRK057ShAw,17997
|
15
|
+
qulab/executor/storage.py,sha256=gI6g28BmKKEZ_Pl-hFwvpiOj3mF8Su-yjj3hfMXs1VY,11630
|
16
|
+
qulab/executor/transform.py,sha256=4DyGXv1Iw36cCPqbqXlsn0Lw6gFjQpp_6Hcta50YQxU,2181
|
17
|
+
qulab/executor/utils.py,sha256=cF6-2jlvlHyTjNHdxXKG04Fjfm3_3wfDQAF1G8DQphk,5686
|
18
18
|
qulab/monitor/__init__.py,sha256=nTHelnDpxRS_fl_B38TsN0njgq8eVTEz9IAnN3NbDlM,42
|
19
19
|
qulab/monitor/__main__.py,sha256=w3yUcqq195LzSnXTkQcuC1RSFRhy4oQ_PEBmucXguME,97
|
20
20
|
qulab/monitor/config.py,sha256=fQ5JcsMApKc1UwANEnIvbDQZl8uYW0tle92SaYtX9lI,744
|
@@ -94,9 +94,9 @@ qulab/visualization/plot_seq.py,sha256=UWTS6p9nfX_7B8ehcYo6UnSTUCjkBsNU9jiOeW2ca
|
|
94
94
|
qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
|
95
95
|
qulab/visualization/rot3d.py,sha256=lMrEJlRLwYe6NMBlGkKYpp_V9CTipOAuDy6QW_cQK00,734
|
96
96
|
qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
|
97
|
-
QuLab-2.7.
|
98
|
-
QuLab-2.7.
|
99
|
-
QuLab-2.7.
|
100
|
-
QuLab-2.7.
|
101
|
-
QuLab-2.7.
|
102
|
-
QuLab-2.7.
|
97
|
+
QuLab-2.7.10.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
|
98
|
+
QuLab-2.7.10.dist-info/METADATA,sha256=-3XSmnAFhNexNzMEufmMAAUF2JfWg2YL_7crqvgyIPg,3699
|
99
|
+
QuLab-2.7.10.dist-info/WHEEL,sha256=Yd3eJSBM2hj8W-ouaiMfFUwQYAS-D6P73Ob9yN5MZd0,114
|
100
|
+
QuLab-2.7.10.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
|
101
|
+
QuLab-2.7.10.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
|
102
|
+
QuLab-2.7.10.dist-info/RECORD,,
|
qulab/__init__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
from .executor.storage import
|
2
|
-
from .executor.storage import
|
1
|
+
from .executor.storage import find_report
|
2
|
+
from .executor.storage import get_report_by_index as get_report
|
3
3
|
from .executor.utils import debug_analyze
|
4
4
|
from .scan import Scan, get_record, load_record, lookup, lookup_list
|
5
5
|
from .version import __version__
|
qulab/executor/cli.py
CHANGED
@@ -149,7 +149,7 @@ def get(key, api):
|
|
149
149
|
|
150
150
|
@click.command()
|
151
151
|
@click.argument('workflow')
|
152
|
-
@click.option('--plot', '-p', is_flag=True, help='Plot the
|
152
|
+
@click.option('--plot', '-p', is_flag=True, help='Plot the report.')
|
153
153
|
@click.option('--no-dependents',
|
154
154
|
'-n',
|
155
155
|
is_flag=True,
|
@@ -221,7 +221,7 @@ def run(workflow, code, data, api, plot, no_dependents, retry, freeze):
|
|
221
221
|
@click.command()
|
222
222
|
@click.argument('workflow')
|
223
223
|
@click.option('--retry', '-r', default=1, type=int, help='Retry times.')
|
224
|
-
@click.option('--plot', '-p', is_flag=True, help='Plot the
|
224
|
+
@click.option('--plot', '-p', is_flag=True, help='Plot the report.')
|
225
225
|
@log_options
|
226
226
|
@command_option('maintain')
|
227
227
|
def maintain(workflow, code, data, api, retry, plot):
|
qulab/executor/load.py
CHANGED
@@ -15,7 +15,7 @@ from typing import Any
|
|
15
15
|
|
16
16
|
from loguru import logger
|
17
17
|
|
18
|
-
from .storage import
|
18
|
+
from .storage import Report
|
19
19
|
|
20
20
|
|
21
21
|
class SetConfigWorkflow():
|
@@ -29,7 +29,7 @@ class SetConfigWorkflow():
|
|
29
29
|
def depends(self):
|
30
30
|
return []
|
31
31
|
|
32
|
-
def check_state(self, history:
|
32
|
+
def check_state(self, history: Report) -> bool:
|
33
33
|
from . import transform
|
34
34
|
try:
|
35
35
|
return self._equal(history.parameters[self.key],
|
@@ -45,21 +45,21 @@ class SetConfigWorkflow():
|
|
45
45
|
value = eval(input(f'"{self.key}": '))
|
46
46
|
return value
|
47
47
|
|
48
|
-
def analyze(self,
|
49
|
-
|
50
|
-
|
51
|
-
return
|
48
|
+
def analyze(self, report: Report, history: Report):
|
49
|
+
report.state = 'OK'
|
50
|
+
report.parameters = {self.key: report.data}
|
51
|
+
return report
|
52
52
|
|
53
53
|
def check(self):
|
54
54
|
return self.calibrate()
|
55
55
|
|
56
|
-
def check_analyze(self,
|
56
|
+
def check_analyze(self, report: Report, history: Report | None):
|
57
57
|
if self.check_state(history):
|
58
|
-
|
59
|
-
|
58
|
+
report.state = 'OK'
|
59
|
+
report.parameters = {self.key: history.data}
|
60
60
|
else:
|
61
|
-
|
62
|
-
return
|
61
|
+
report.state = 'Outdated'
|
62
|
+
return report
|
63
63
|
|
64
64
|
@staticmethod
|
65
65
|
def _equal(a, b):
|
qulab/executor/schedule.py
CHANGED
@@ -7,28 +7,28 @@ from pathlib import Path
|
|
7
7
|
from loguru import logger
|
8
8
|
|
9
9
|
from .load import WorkflowType, get_dependents
|
10
|
-
from .storage import (
|
11
|
-
|
10
|
+
from .storage import (Report, find_report, get_head, get_heads, renew_report,
|
11
|
+
revoke_report, save_item, save_report)
|
12
12
|
from .transform import current_config, obey_the_oracle, update_parameters
|
13
13
|
|
14
14
|
__session_id = None
|
15
15
|
__session_cache = {}
|
16
16
|
|
17
17
|
|
18
|
-
def set_cache(session_id, key,
|
18
|
+
def set_cache(session_id, key, report: Report):
|
19
19
|
global __session_id
|
20
20
|
if __session_id is None:
|
21
21
|
__session_id = session_id
|
22
22
|
if __session_id != session_id:
|
23
23
|
__session_cache.clear()
|
24
|
-
if
|
25
|
-
__session_cache[key] =
|
24
|
+
if report.workflow.startswith('cfg:'):
|
25
|
+
__session_cache[key] = report
|
26
26
|
else:
|
27
|
-
__session_cache[key] =
|
27
|
+
__session_cache[key] = report.base_path, report.path
|
28
28
|
|
29
29
|
|
30
|
-
def get_cache(session_id, key) ->
|
31
|
-
from .storage import
|
30
|
+
def get_cache(session_id, key) -> Report:
|
31
|
+
from .storage import load_report
|
32
32
|
global __session_id
|
33
33
|
if __session_id is None or __session_id != session_id:
|
34
34
|
return None
|
@@ -37,8 +37,8 @@ def get_cache(session_id, key) -> Result:
|
|
37
37
|
return None
|
38
38
|
if isinstance(index, tuple):
|
39
39
|
base_path, path = index
|
40
|
-
return
|
41
|
-
elif isinstance(index,
|
40
|
+
return load_report(base_path, path)
|
41
|
+
elif isinstance(index, Report):
|
42
42
|
return index
|
43
43
|
else:
|
44
44
|
return None
|
@@ -56,19 +56,29 @@ def is_pickleable(obj) -> bool:
|
|
56
56
|
return False
|
57
57
|
|
58
58
|
|
59
|
-
def
|
60
|
-
if not isinstance(
|
61
|
-
raise TypeError(f'"{script}" : "{method}" must return a
|
62
|
-
if not is_pickleable(
|
59
|
+
def veryfy_analyzed_report(report: Report, script: str, method: str):
|
60
|
+
if not isinstance(report, Report):
|
61
|
+
raise TypeError(f'"{script}" : "{method}" must return a Report object')
|
62
|
+
if not is_pickleable(report.parameters):
|
63
63
|
raise TypeError(
|
64
64
|
f'"{script}" : "{method}" return not pickleable data in .parameters'
|
65
65
|
)
|
66
|
-
if not is_pickleable(
|
66
|
+
if not is_pickleable(report.other_infomation):
|
67
67
|
raise TypeError(
|
68
68
|
f'"{script}" : "{method}" return not pickleable data in .other_infomation'
|
69
69
|
)
|
70
70
|
|
71
71
|
|
72
|
+
def get_source(workflow: WorkflowType, code_path: str | Path) -> str:
|
73
|
+
if isinstance(code_path, str):
|
74
|
+
code_path = Path(code_path)
|
75
|
+
try:
|
76
|
+
with open(code_path / workflow.__workflow_id__, 'r') as f:
|
77
|
+
return f.read()
|
78
|
+
except:
|
79
|
+
return ''
|
80
|
+
|
81
|
+
|
72
82
|
def check_state(workflow: WorkflowType, code_path: str | Path,
|
73
83
|
state_path: str | Path) -> bool:
|
74
84
|
"""
|
@@ -80,8 +90,8 @@ def check_state(workflow: WorkflowType, code_path: str | Path,
|
|
80
90
|
4. All dependencies pass check state.
|
81
91
|
"""
|
82
92
|
logger.debug(f'check_state: "{workflow.__workflow_id__}"')
|
83
|
-
|
84
|
-
if not
|
93
|
+
report = find_report(workflow.__workflow_id__, state_path)
|
94
|
+
if not report:
|
85
95
|
logger.debug(
|
86
96
|
f'check_state failed: No history found for "{workflow.__workflow_id__}"'
|
87
97
|
)
|
@@ -90,23 +100,28 @@ def check_state(workflow: WorkflowType, code_path: str | Path,
|
|
90
100
|
logger.debug(
|
91
101
|
f'check_state: "{workflow.__workflow_id__}" has custom check_state method'
|
92
102
|
)
|
93
|
-
return workflow.check_state(
|
103
|
+
return workflow.check_state(report)
|
104
|
+
if datetime.fromtimestamp(workflow.__mtime__) > report.checked_time:
|
105
|
+
logger.debug(
|
106
|
+
f'check_state failed: "{workflow.__workflow_id__}" has been modified after last calibration'
|
107
|
+
)
|
108
|
+
return False
|
94
109
|
if workflow.__timeout__ is not None and datetime.now(
|
95
|
-
) >
|
110
|
+
) > report.checked_time + timedelta(seconds=workflow.__timeout__):
|
96
111
|
logger.debug(
|
97
112
|
f'check_state failed: "{workflow.__workflow_id__}" has expired')
|
98
113
|
return False
|
99
|
-
if not
|
114
|
+
if not report.in_spec:
|
100
115
|
logger.debug(
|
101
116
|
f'check_state failed: "{workflow.__workflow_id__}" is out of spec')
|
102
117
|
return False
|
103
|
-
if
|
118
|
+
if report.bad_data:
|
104
119
|
logger.debug(
|
105
120
|
f'check_state failed: "{workflow.__workflow_id__}" has bad data')
|
106
121
|
return False
|
107
122
|
for n in get_dependents(workflow, code_path):
|
108
|
-
r =
|
109
|
-
if r is None or r.checked_time >
|
123
|
+
r = find_report(n.__workflow_id__, state_path)
|
124
|
+
if r is None or r.checked_time > report.checked_time:
|
110
125
|
logger.debug(
|
111
126
|
f'check_state failed: "{workflow.__workflow_id__}" has outdated dependencies'
|
112
127
|
)
|
@@ -120,71 +135,146 @@ def check_state(workflow: WorkflowType, code_path: str | Path,
|
|
120
135
|
return True
|
121
136
|
|
122
137
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
138
|
+
@logger.catch()
|
139
|
+
def call_plot(node: WorkflowType, report: Report, check=False):
|
140
|
+
if hasattr(node, 'plot') and callable(node.plot):
|
141
|
+
node.plot(report)
|
142
|
+
|
143
|
+
|
144
|
+
def call_check(workflow: WorkflowType, session_id: str, state_path: Path):
|
145
|
+
report = get_cache(session_id, (workflow, 'check'))
|
146
|
+
if report is not None:
|
147
|
+
logger.debug(f'Cache hit for "{workflow.__workflow_id__}:check"')
|
148
|
+
return report
|
149
|
+
|
150
|
+
data = workflow.check()
|
151
|
+
if not is_pickleable(data):
|
152
|
+
raise TypeError(
|
153
|
+
f'"{workflow.__workflow_id__}" : "check" return not pickleable data'
|
154
|
+
)
|
155
|
+
report = Report(workflow=workflow.__workflow_id__,
|
156
|
+
data=data,
|
157
|
+
config_path=current_config(state_path),
|
158
|
+
base_path=state_path,
|
159
|
+
heads=get_heads(state_path),
|
160
|
+
previous_path=get_head(workflow.__workflow_id__,
|
161
|
+
state_path),
|
162
|
+
script_path=save_item(get_source(workflow, state_path),
|
163
|
+
state_path))
|
164
|
+
|
165
|
+
save_report(workflow.__workflow_id__, report, state_path)
|
166
|
+
|
167
|
+
set_cache(session_id, (workflow, 'check'), report)
|
168
|
+
return report
|
169
|
+
|
170
|
+
|
171
|
+
def call_calibrate(workflow: WorkflowType, session_id: str, state_path: Path):
|
172
|
+
report = get_cache(session_id, (workflow, 'calibrate'))
|
173
|
+
if report is not None:
|
174
|
+
logger.debug(f'Cache hit for "{workflow.__workflow_id__}:calibrate"')
|
175
|
+
return report
|
176
|
+
|
177
|
+
data = workflow.calibrate()
|
178
|
+
if not is_pickleable(data):
|
179
|
+
raise TypeError(
|
180
|
+
f'"{workflow.__workflow_id__}" : "calibrate" return not pickleable data'
|
181
|
+
)
|
182
|
+
report = Report(workflow=workflow.__workflow_id__,
|
183
|
+
data=data,
|
184
|
+
config_path=current_config(state_path),
|
185
|
+
base_path=state_path,
|
186
|
+
heads=get_heads(state_path),
|
187
|
+
previous_path=get_head(workflow.__workflow_id__,
|
188
|
+
state_path),
|
189
|
+
script_path=save_item(get_source(workflow, state_path),
|
190
|
+
state_path))
|
191
|
+
|
192
|
+
save_report(workflow.__workflow_id__, report, state_path)
|
193
|
+
|
194
|
+
set_cache(session_id, (workflow, 'calibrate'), report)
|
195
|
+
return report
|
196
|
+
|
197
|
+
|
198
|
+
def call_check_analyzer(node: WorkflowType,
|
199
|
+
report: Report,
|
200
|
+
history: Report | None,
|
201
|
+
state_path: Path,
|
202
|
+
plot=False) -> Report:
|
203
|
+
report = node.check_analyze(report, history=history)
|
204
|
+
veryfy_analyzed_report(report, node.__workflow_id__, "check_analyze")
|
205
|
+
report.fully_calibrated = False
|
206
|
+
if report.in_spec:
|
207
|
+
logger.debug(
|
208
|
+
f'"{node.__workflow_id__}": checked in spec, renewing report')
|
209
|
+
if report.previous is not None:
|
210
|
+
renew_report(node.__workflow_id__, report.previous, state_path)
|
211
|
+
else:
|
212
|
+
renew_report(node.__workflow_id__, report, state_path)
|
132
213
|
else:
|
133
|
-
|
134
|
-
|
135
|
-
if
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
history=history,
|
141
|
-
system_state=get_heads(result.base_path))
|
142
|
-
except Exception as e:
|
143
|
-
logger.exception(e)
|
144
|
-
result.oracle = {}
|
145
|
-
if not isinstance(result, Result):
|
146
|
-
raise TypeError(
|
147
|
-
f'"{node.__workflow_id__}" : function "oracle" must return a Result object'
|
148
|
-
)
|
149
|
-
if not is_pickleable(result.oracle):
|
150
|
-
raise TypeError(
|
151
|
-
f'"{node.__workflow_id__}" : function "oracle" return not pickleable data'
|
152
|
-
)
|
153
|
-
result.fully_calibrated = True
|
154
|
-
if plot:
|
155
|
-
call_plot(node, result)
|
156
|
-
return result
|
214
|
+
logger.debug(
|
215
|
+
f'"{node.__workflow_id__}": checked out of spec, revoking report')
|
216
|
+
if report.previous is not None:
|
217
|
+
revoke_report(node.__workflow_id__, report.previous, state_path)
|
218
|
+
else:
|
219
|
+
revoke_report(node.__workflow_id__, report, state_path)
|
220
|
+
return report
|
157
221
|
|
158
222
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
223
|
+
def call_analyzer(node: WorkflowType,
|
224
|
+
report: Report,
|
225
|
+
history: Report | None,
|
226
|
+
state_path: Path,
|
227
|
+
plot=False) -> Report:
|
228
|
+
|
229
|
+
report = node.analyze(report, history=history)
|
230
|
+
veryfy_analyzed_report(report, node.__workflow_id__, "analyze")
|
231
|
+
if hasattr(node, 'oracle') and callable(node.oracle):
|
232
|
+
logger.debug(
|
233
|
+
f'"{node.__workflow_id__}" has oracle method, calling ...')
|
234
|
+
try:
|
235
|
+
report = node.oracle(report,
|
236
|
+
history=history,
|
237
|
+
system_state=get_heads(report.base_path))
|
238
|
+
except Exception as e:
|
239
|
+
logger.exception(e)
|
240
|
+
report.oracle = {}
|
241
|
+
if not isinstance(report, Report):
|
242
|
+
raise TypeError(
|
243
|
+
f'"{node.__workflow_id__}" : function "oracle" must return a Report object'
|
244
|
+
)
|
245
|
+
if not is_pickleable(report.oracle):
|
246
|
+
raise TypeError(
|
247
|
+
f'"{node.__workflow_id__}" : function "oracle" return not pickleable data'
|
248
|
+
)
|
249
|
+
report.fully_calibrated = True
|
250
|
+
save_report(node.__workflow_id__, report, state_path, overwrite=True)
|
251
|
+
if plot:
|
252
|
+
call_plot(node, report)
|
253
|
+
return report
|
163
254
|
|
164
255
|
|
165
|
-
def check_data(workflow: WorkflowType,
|
166
|
-
|
256
|
+
def check_data(workflow: WorkflowType, state_path: str | Path, plot: bool,
|
257
|
+
session_id: str) -> Report:
|
167
258
|
"""
|
168
259
|
check data answers two questions:
|
169
260
|
Is the parameter associated with this cal in spec,
|
170
261
|
and is the cal scan working as expected?
|
171
262
|
"""
|
172
|
-
|
173
|
-
if result is not None:
|
174
|
-
logger.debug(f'Cache hit for "{workflow.__workflow_id__}:check_data"')
|
175
|
-
return result
|
176
|
-
|
177
|
-
history = find_result(workflow.__workflow_id__, state_path)
|
263
|
+
history = find_report(workflow.__workflow_id__, state_path)
|
178
264
|
|
179
265
|
if history is None:
|
180
266
|
logger.debug(f'No history found for "{workflow.__workflow_id__}"')
|
181
|
-
|
267
|
+
report = Report(workflow=workflow.__workflow_id__,
|
182
268
|
config_path=current_config(state_path),
|
183
269
|
base_path=state_path,
|
184
|
-
heads=get_heads(state_path)
|
185
|
-
|
186
|
-
|
187
|
-
|
270
|
+
heads=get_heads(state_path),
|
271
|
+
previous_path=get_head(workflow.__workflow_id__,
|
272
|
+
state_path),
|
273
|
+
script_path=save_item(get_source(workflow, state_path),
|
274
|
+
state_path))
|
275
|
+
report.in_spec = False
|
276
|
+
report.bad_data = False
|
277
|
+
return report
|
188
278
|
|
189
279
|
if history.bad_data:
|
190
280
|
logger.debug(
|
@@ -202,92 +292,43 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
|
|
202
292
|
workflow, 'check_analyze') and callable(workflow.check_analyze):
|
203
293
|
logger.debug(
|
204
294
|
f'Checking "{workflow.__workflow_id__}" with "check" method ...')
|
205
|
-
|
206
|
-
|
207
|
-
raise TypeError(
|
208
|
-
f'"{workflow.__workflow_id__}" : "check" return not pickleable data'
|
209
|
-
)
|
210
|
-
result = Result(workflow=workflow.__workflow_id__,
|
211
|
-
data=data,
|
212
|
-
config_path=current_config(state_path),
|
213
|
-
base_path=state_path,
|
214
|
-
heads=get_heads(state_path))
|
215
|
-
#save_result(workflow.__workflow_id__, result, state_path)
|
295
|
+
|
296
|
+
report = call_check(workflow, session_id, state_path)
|
216
297
|
|
217
298
|
logger.debug(f'Checked "{workflow.__workflow_id__}" !')
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
if result.in_spec:
|
224
|
-
logger.debug(
|
225
|
-
f'"{workflow.__workflow_id__}": checked in spec, renewing result'
|
226
|
-
)
|
227
|
-
renew_result(workflow.__workflow_id__, state_path)
|
228
|
-
else:
|
229
|
-
logger.debug(
|
230
|
-
f'"{workflow.__workflow_id__}": checked out of spec, revoking result'
|
231
|
-
)
|
232
|
-
revoke_result(workflow.__workflow_id__, state_path)
|
299
|
+
report = call_check_analyzer(workflow,
|
300
|
+
report,
|
301
|
+
history,
|
302
|
+
state_path,
|
303
|
+
plot=plot)
|
233
304
|
else:
|
234
305
|
logger.debug(
|
235
306
|
f'Checking "{workflow.__workflow_id__}" with "calibrate" method ...'
|
236
307
|
)
|
237
|
-
|
238
|
-
|
239
|
-
raise TypeError(
|
240
|
-
f'"{workflow.__workflow_id__}" : "calibrate" return not pickleable data'
|
241
|
-
)
|
242
|
-
result = Result(workflow=workflow.__workflow_id__,
|
243
|
-
data=data,
|
244
|
-
config_path=current_config(state_path),
|
245
|
-
base_path=state_path,
|
246
|
-
heads=get_heads(state_path))
|
247
|
-
save_result(workflow.__workflow_id__, result, state_path)
|
308
|
+
|
309
|
+
report = call_calibrate(workflow, session_id, state_path)
|
248
310
|
|
249
311
|
logger.debug(f'Calibrated "{workflow.__workflow_id__}" !')
|
250
|
-
|
251
|
-
|
312
|
+
report = call_analyzer(workflow,
|
313
|
+
report,
|
252
314
|
history,
|
253
|
-
|
315
|
+
state_path,
|
254
316
|
plot=plot)
|
255
|
-
|
256
|
-
result,
|
257
|
-
state_path,
|
258
|
-
overwrite=True)
|
317
|
+
return report
|
259
318
|
|
260
|
-
set_cache(session_id, (workflow, 'check_data'), result)
|
261
|
-
return result
|
262
319
|
|
320
|
+
def calibrate(workflow: WorkflowType, state_path: str | Path, plot: bool,
|
321
|
+
session_id: str) -> Report:
|
322
|
+
history = find_report(workflow.__workflow_id__, state_path)
|
263
323
|
|
264
|
-
|
265
|
-
state_path: str | Path, plot: bool, session_id: str) -> Result:
|
266
|
-
result = get_cache(session_id, (workflow, 'calibrate'))
|
267
|
-
if result is not None:
|
268
|
-
logger.debug(f'Cache hit for "{workflow.__workflow_id__}:calibrate"')
|
269
|
-
return result
|
324
|
+
logger.debug(f'Calibrating "{workflow.__workflow_id__}" ...')
|
270
325
|
|
271
|
-
|
326
|
+
report = call_calibrate(workflow, session_id, state_path)
|
272
327
|
|
273
|
-
logger.debug(f'Calibrating "{workflow.__workflow_id__}" ...')
|
274
|
-
data = workflow.calibrate()
|
275
|
-
if not is_pickleable(data):
|
276
|
-
raise TypeError(
|
277
|
-
f'"{workflow.__workflow_id__}" : "calibrate" return not pickleable data'
|
278
|
-
)
|
279
|
-
result = Result(workflow=workflow.__workflow_id__,
|
280
|
-
data=data,
|
281
|
-
config_path=current_config(state_path),
|
282
|
-
base_path=state_path,
|
283
|
-
heads=get_heads(state_path))
|
284
|
-
save_result(workflow.__workflow_id__, result, state_path)
|
285
328
|
logger.debug(f'Calibrated "{workflow.__workflow_id__}" !')
|
286
|
-
result = call_analyzer(workflow, result, history, check=False, plot=plot)
|
287
|
-
save_result(workflow.__workflow_id__, result, state_path, overwrite=True)
|
288
329
|
|
289
|
-
|
290
|
-
return
|
330
|
+
report = call_analyzer(workflow, report, history, state_path, plot=plot)
|
331
|
+
return report
|
291
332
|
|
292
333
|
|
293
334
|
def diagnose(workflow: WorkflowType, code_path: str | Path,
|
@@ -297,16 +338,16 @@ def diagnose(workflow: WorkflowType, code_path: str | Path,
|
|
297
338
|
'''
|
298
339
|
logger.debug(f'diagnose "{workflow.__workflow_id__}"')
|
299
340
|
# check_data
|
300
|
-
|
341
|
+
report = check_data(workflow, state_path, plot, session_id)
|
301
342
|
# in spec case
|
302
|
-
if
|
343
|
+
if report.in_spec:
|
303
344
|
logger.debug(
|
304
345
|
f'"{workflow.__workflow_id__}": Checked! In spec, no need to diagnose'
|
305
346
|
)
|
306
347
|
return False
|
307
348
|
# bad data case
|
308
349
|
recalibrated = []
|
309
|
-
if
|
350
|
+
if report.bad_data:
|
310
351
|
logger.debug(
|
311
352
|
f'"{workflow.__workflow_id__}": Bad data, diagnosing dependents')
|
312
353
|
recalibrated = [
|
@@ -314,7 +355,7 @@ def diagnose(workflow: WorkflowType, code_path: str | Path,
|
|
314
355
|
for n in get_dependents(workflow, code_path)
|
315
356
|
]
|
316
357
|
if not any(recalibrated):
|
317
|
-
if
|
358
|
+
if report.bad_data:
|
318
359
|
raise CalibrationFailedError(
|
319
360
|
f'"{workflow.__workflow_id__}": bad data but no dependents recalibrated.'
|
320
361
|
)
|
@@ -325,27 +366,27 @@ def diagnose(workflow: WorkflowType, code_path: str | Path,
|
|
325
366
|
logger.debug(
|
326
367
|
f'recalibrate "{workflow.__workflow_id__}" because some dependents recalibrated.'
|
327
368
|
)
|
328
|
-
elif not
|
369
|
+
elif not report.in_spec and not report.bad_data:
|
329
370
|
logger.debug(
|
330
371
|
f'recalibrate "{workflow.__workflow_id__}" because out of spec.')
|
331
|
-
elif
|
372
|
+
elif report.in_spec:
|
332
373
|
logger.error(
|
333
374
|
f'Never reach: recalibrate "{workflow.__workflow_id__}" because in spec.'
|
334
375
|
)
|
335
|
-
elif
|
376
|
+
elif report.bad_data:
|
336
377
|
logger.error(
|
337
378
|
f'Never reach: recalibrate "{workflow.__workflow_id__}" because bad data.'
|
338
379
|
)
|
339
380
|
else:
|
340
381
|
logger.error(f'Never reach: recalibrate "{workflow.__workflow_id__}"')
|
341
382
|
|
342
|
-
|
343
|
-
if
|
344
|
-
obey_the_oracle(
|
383
|
+
report = calibrate(workflow, state_path, plot, session_id)
|
384
|
+
if report.bad_data or not report.in_spec:
|
385
|
+
obey_the_oracle(report, state_path)
|
345
386
|
raise CalibrationFailedError(
|
346
387
|
f'"{workflow.__workflow_id__}": All dependents passed, but calibration failed!'
|
347
388
|
)
|
348
|
-
update_parameters(
|
389
|
+
update_parameters(report, state_path)
|
349
390
|
return True
|
350
391
|
|
351
392
|
|
@@ -382,13 +423,13 @@ def maintain(workflow: WorkflowType,
|
|
382
423
|
f'"{workflow.__workflow_id__}": In spec, no need to maintain')
|
383
424
|
return
|
384
425
|
# check_data
|
385
|
-
|
386
|
-
if
|
426
|
+
report = check_data(workflow, state_path, plot, session_id)
|
427
|
+
if report.in_spec:
|
387
428
|
if not run:
|
388
429
|
logger.debug(
|
389
430
|
f'"{workflow.__workflow_id__}": In spec, no need to maintain')
|
390
431
|
return
|
391
|
-
elif
|
432
|
+
elif report.bad_data:
|
392
433
|
logger.debug(
|
393
434
|
f'"{workflow.__workflow_id__}": Bad data, diagnosing dependents')
|
394
435
|
for n in get_dependents(workflow, code_path):
|
@@ -401,15 +442,15 @@ def maintain(workflow: WorkflowType,
|
|
401
442
|
f'"{workflow.__workflow_id__}": All dependents diagnosed')
|
402
443
|
# calibrate
|
403
444
|
logger.debug(f'recalibrate "{workflow.__workflow_id__}"')
|
404
|
-
|
405
|
-
if
|
445
|
+
report = calibrate(workflow, state_path, plot, session_id)
|
446
|
+
if report.bad_data or not report.in_spec:
|
406
447
|
if not freeze:
|
407
|
-
obey_the_oracle(
|
448
|
+
obey_the_oracle(report, state_path)
|
408
449
|
raise CalibrationFailedError(
|
409
450
|
f'"{workflow.__workflow_id__}": All dependents passed, but calibration failed!'
|
410
451
|
)
|
411
452
|
if not freeze:
|
412
|
-
update_parameters(
|
453
|
+
update_parameters(report, state_path)
|
413
454
|
return
|
414
455
|
|
415
456
|
|
@@ -421,17 +462,13 @@ def run(workflow: WorkflowType,
|
|
421
462
|
freeze: bool = False):
|
422
463
|
session_id = uuid.uuid4().hex
|
423
464
|
logger.debug(f'run "{workflow.__workflow_id__}" without dependences.')
|
424
|
-
|
425
|
-
|
426
|
-
state_path,
|
427
|
-
plot,
|
428
|
-
session_id=session_id)
|
429
|
-
if result.bad_data or not result.in_spec:
|
465
|
+
report = calibrate(workflow, state_path, plot, session_id=session_id)
|
466
|
+
if report.bad_data or not report.in_spec:
|
430
467
|
if not freeze:
|
431
|
-
obey_the_oracle(
|
468
|
+
obey_the_oracle(report, state_path)
|
432
469
|
raise CalibrationFailedError(
|
433
470
|
f'"{workflow.__workflow_id__}": All dependents passed, but calibration failed!'
|
434
471
|
)
|
435
472
|
if not freeze:
|
436
|
-
update_parameters(
|
473
|
+
update_parameters(report, state_path)
|
437
474
|
return
|
qulab/executor/storage.py
CHANGED
@@ -16,7 +16,7 @@ __current_config_cache = None
|
|
16
16
|
|
17
17
|
|
18
18
|
@dataclass
|
19
|
-
class
|
19
|
+
class Report():
|
20
20
|
workflow: str = ''
|
21
21
|
in_spec: bool = False
|
22
22
|
bad_data: bool = False
|
@@ -34,11 +34,12 @@ class Result():
|
|
34
34
|
base_path: Path | None = field(default=None, repr=False)
|
35
35
|
path: Path | None = field(default=None, repr=False)
|
36
36
|
config_path: Path | None = field(default=None, repr=False)
|
37
|
+
script_path: Path | None = field(default=None, repr=False)
|
37
38
|
|
38
39
|
@property
|
39
40
|
def previous(self):
|
40
41
|
if self.previous_path is not None and self.base_path is not None:
|
41
|
-
return
|
42
|
+
return load_report(self.previous_path, self.base_path)
|
42
43
|
else:
|
43
44
|
return None
|
44
45
|
|
@@ -54,13 +55,6 @@ class Result():
|
|
54
55
|
state = 'Outdated'
|
55
56
|
return state
|
56
57
|
|
57
|
-
@property
|
58
|
-
def config(self):
|
59
|
-
if self.config_path is not None and self.base_path is not None:
|
60
|
-
return load_config(self.config_path, self.base_path)
|
61
|
-
else:
|
62
|
-
return None
|
63
|
-
|
64
58
|
@state.setter
|
65
59
|
def state(self, state: Literal['OK', 'Bad', 'Outdated', 'In spec',
|
66
60
|
'Out of spec', 'Bad data']):
|
@@ -80,6 +74,20 @@ class Result():
|
|
80
74
|
self.bad_data = False
|
81
75
|
self.in_spec = False
|
82
76
|
|
77
|
+
@property
|
78
|
+
def config(self):
|
79
|
+
if self.config_path is not None and self.base_path is not None:
|
80
|
+
return load_item(self.config_path, self.base_path)
|
81
|
+
else:
|
82
|
+
return None
|
83
|
+
|
84
|
+
@property
|
85
|
+
def script(self):
|
86
|
+
if self.script_path is not None and self.base_path is not None:
|
87
|
+
return load_item(self.script_path, self.base_path)
|
88
|
+
else:
|
89
|
+
return None
|
90
|
+
|
83
91
|
|
84
92
|
def random_path(base: Path) -> Path:
|
85
93
|
while True:
|
@@ -89,7 +97,7 @@ def random_path(base: Path) -> Path:
|
|
89
97
|
return path
|
90
98
|
|
91
99
|
|
92
|
-
def save_config_key_history(key: str,
|
100
|
+
def save_config_key_history(key: str, report: Report,
|
93
101
|
base_path: str | Path) -> int:
|
94
102
|
global __current_config_cache
|
95
103
|
base_path = Path(base_path) / 'state'
|
@@ -103,14 +111,14 @@ def save_config_key_history(key: str, result: Result,
|
|
103
111
|
__current_config_cache = {}
|
104
112
|
|
105
113
|
__current_config_cache[
|
106
|
-
key] =
|
114
|
+
key] = report.data, report.calibrated_time, report.checked_time
|
107
115
|
|
108
116
|
with open(base_path / 'parameters.pkl', 'wb') as f:
|
109
117
|
pickle.dump(__current_config_cache, f)
|
110
118
|
return 0
|
111
119
|
|
112
120
|
|
113
|
-
def find_config_key_history(key: str, base_path: str | Path) ->
|
121
|
+
def find_config_key_history(key: str, base_path: str | Path) -> Report | None:
|
114
122
|
global __current_config_cache
|
115
123
|
base_path = Path(base_path) / 'state'
|
116
124
|
if __current_config_cache is None:
|
@@ -123,7 +131,7 @@ def find_config_key_history(key: str, base_path: str | Path) -> Result | None:
|
|
123
131
|
if key in __current_config_cache:
|
124
132
|
value, calibrated_time, checked_time = __current_config_cache.get(
|
125
133
|
key, None)
|
126
|
-
|
134
|
+
report = Report(
|
127
135
|
workflow=f'cfg:{key}',
|
128
136
|
bad_data=False,
|
129
137
|
in_spec=True,
|
@@ -133,64 +141,65 @@ def find_config_key_history(key: str, base_path: str | Path) -> Result | None:
|
|
133
141
|
calibrated_time=calibrated_time,
|
134
142
|
checked_time=checked_time,
|
135
143
|
)
|
136
|
-
return
|
144
|
+
return report
|
137
145
|
return None
|
138
146
|
|
139
147
|
|
140
|
-
def
|
141
|
-
|
148
|
+
def save_report(workflow: str,
|
149
|
+
report: Report,
|
142
150
|
base_path: str | Path,
|
143
|
-
overwrite: bool = False
|
151
|
+
overwrite: bool = False,
|
152
|
+
refresh_heads: bool = True) -> int:
|
144
153
|
if workflow.startswith("cfg:"):
|
145
|
-
return save_config_key_history(workflow[4:],
|
154
|
+
return save_config_key_history(workflow[4:], report, base_path)
|
146
155
|
|
147
156
|
logger.debug(
|
148
|
-
f'Saving
|
157
|
+
f'Saving report for "{workflow}", {report.in_spec=}, {report.bad_data=}, {report.fully_calibrated=}'
|
149
158
|
)
|
150
159
|
base_path = Path(base_path)
|
160
|
+
try:
|
161
|
+
buf = lzma.compress(pickle.dumps(report))
|
162
|
+
except:
|
163
|
+
raise ValueError(f"Can't pickle report for {workflow}")
|
151
164
|
if overwrite:
|
152
|
-
|
153
|
-
path = result.path
|
165
|
+
path = report.path
|
154
166
|
if path is None:
|
155
|
-
path
|
156
|
-
|
157
|
-
with open(base_path / 'objects' / path, "rb") as f:
|
167
|
+
raise ValueError("Report path is None, can't overwrite.")
|
168
|
+
with open(base_path / 'reports' / path, "rb") as f:
|
158
169
|
index = int.from_bytes(f.read(8), 'big')
|
159
|
-
|
170
|
+
report.index = index
|
160
171
|
else:
|
161
|
-
|
162
|
-
|
163
|
-
path = random_path(base_path / 'objects')
|
164
|
-
(base_path / 'objects' / path).parent.mkdir(parents=True,
|
172
|
+
path = random_path(base_path / 'reports')
|
173
|
+
(base_path / 'reports' / path).parent.mkdir(parents=True,
|
165
174
|
exist_ok=True)
|
166
|
-
|
167
|
-
|
175
|
+
report.path = path
|
176
|
+
report.index = create_index("report",
|
168
177
|
base_path,
|
169
178
|
context=str(path),
|
170
179
|
width=35)
|
171
|
-
|
172
|
-
|
173
|
-
f.write(result.index.to_bytes(8, 'big'))
|
180
|
+
with open(base_path / 'reports' / path, "wb") as f:
|
181
|
+
f.write(report.index.to_bytes(8, 'big'))
|
174
182
|
f.write(buf)
|
175
|
-
|
176
|
-
|
183
|
+
if refresh_heads:
|
184
|
+
set_head(workflow, path, base_path)
|
185
|
+
return report.index
|
177
186
|
|
178
187
|
|
179
|
-
def
|
188
|
+
def load_report(path: str | Path, base_path: str | Path) -> Report | None:
|
180
189
|
base_path = Path(base_path)
|
181
|
-
path = base_path / '
|
190
|
+
path = base_path / 'reports' / path
|
182
191
|
|
183
|
-
with open(base_path / '
|
192
|
+
with open(base_path / 'reports' / path, "rb") as f:
|
184
193
|
index = int.from_bytes(f.read(8), 'big')
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
return
|
194
|
+
report = pickle.loads(lzma.decompress(f.read()))
|
195
|
+
report.base_path = base_path
|
196
|
+
report.index = index
|
197
|
+
return report
|
189
198
|
|
190
199
|
|
191
|
-
def
|
200
|
+
def find_report(
|
192
201
|
workflow: str, base_path: str | Path = get_config_value("data", Path)
|
193
|
-
) ->
|
202
|
+
) -> Report | None:
|
194
203
|
if workflow.startswith("cfg:"):
|
195
204
|
return find_config_key_history(workflow[4:], base_path)
|
196
205
|
|
@@ -198,25 +207,33 @@ def find_result(
|
|
198
207
|
path = get_head(workflow, base_path)
|
199
208
|
if path is None:
|
200
209
|
return None
|
201
|
-
return
|
202
|
-
|
203
|
-
|
204
|
-
def
|
205
|
-
logger.debug(f'Renewing
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
+
return load_report(path, base_path)
|
211
|
+
|
212
|
+
|
213
|
+
def renew_report(workflow: str, report: Report | None, base_path: str | Path):
|
214
|
+
logger.debug(f'Renewing report for "{workflow}"')
|
215
|
+
if report is not None:
|
216
|
+
report.checked_time = datetime.now()
|
217
|
+
return save_report(workflow,
|
218
|
+
report,
|
219
|
+
base_path,
|
220
|
+
overwrite=True,
|
221
|
+
refresh_heads=True)
|
222
|
+
else:
|
223
|
+
raise ValueError(f"Can't renew report for {workflow}")
|
210
224
|
|
211
225
|
|
212
|
-
def
|
213
|
-
logger.debug(f'Revoking
|
226
|
+
def revoke_report(workflow: str, report: Report | None, base_path: str | Path):
|
227
|
+
logger.debug(f'Revoking report for "{workflow}"')
|
214
228
|
base_path = Path(base_path)
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
229
|
+
if report is not None:
|
230
|
+
report.in_spec = False
|
231
|
+
report.previous_path = report.path
|
232
|
+
return save_report(workflow,
|
233
|
+
report,
|
234
|
+
base_path,
|
235
|
+
overwrite=False,
|
236
|
+
refresh_heads=True)
|
220
237
|
|
221
238
|
|
222
239
|
def set_head(workflow: str, path: Path, base_path: str | Path):
|
@@ -296,28 +313,27 @@ def query_index(name: str, base_path: str | Path, index: int):
|
|
296
313
|
return context.rstrip()
|
297
314
|
|
298
315
|
|
299
|
-
def
|
316
|
+
def get_report_by_index(
|
300
317
|
index: int, base_path: str | Path = get_config_value("data", Path)
|
301
|
-
) ->
|
318
|
+
) -> Report | None:
|
302
319
|
try:
|
303
|
-
path = query_index("
|
304
|
-
return
|
320
|
+
path = query_index("report", base_path, index)
|
321
|
+
return load_report(path, base_path)
|
305
322
|
except:
|
306
323
|
return None
|
307
324
|
|
308
325
|
|
309
|
-
def
|
310
|
-
|
311
|
-
buf = pickle.dumps(
|
326
|
+
def save_item(item, data_path):
|
327
|
+
salt = 0
|
328
|
+
buf = pickle.dumps(item)
|
312
329
|
buf = lzma.compress(buf)
|
313
330
|
h = hashlib.md5(buf)
|
314
331
|
|
315
332
|
while True:
|
316
|
-
|
317
|
-
h.update(salt)
|
333
|
+
h.update(f"{salt}".encode())
|
318
334
|
hashstr = h.hexdigest()
|
319
|
-
|
320
|
-
path = Path(data_path) / '
|
335
|
+
item_id = Path(hashstr[:2]) / hashstr[2:4] / hashstr[4:]
|
336
|
+
path = Path(data_path) / 'items' / item_id
|
321
337
|
if not path.exists():
|
322
338
|
path.parent.mkdir(parents=True, exist_ok=True)
|
323
339
|
with open(path, 'wb') as f:
|
@@ -325,13 +341,13 @@ def save_config(cfg, data_path):
|
|
325
341
|
break
|
326
342
|
elif path.read_bytes() == buf:
|
327
343
|
break
|
328
|
-
|
329
|
-
return str(
|
344
|
+
salt += 1
|
345
|
+
return str(item_id)
|
330
346
|
|
331
347
|
|
332
|
-
@lru_cache(maxsize=
|
333
|
-
def
|
334
|
-
path = Path(data_path) / '
|
348
|
+
@lru_cache(maxsize=4096)
|
349
|
+
def load_item(id, data_path):
|
350
|
+
path = Path(data_path) / 'items' / id
|
335
351
|
with open(path, 'rb') as f:
|
336
352
|
buf = f.read()
|
337
353
|
cfg = pickle.loads(lzma.decompress(buf))
|
qulab/executor/transform.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from .storage import
|
1
|
+
from .storage import Report, save_item
|
2
2
|
|
3
3
|
__current_config_id = None
|
4
4
|
|
@@ -43,25 +43,25 @@ def _export_config() -> dict:
|
|
43
43
|
return parameters
|
44
44
|
|
45
45
|
|
46
|
-
def obey_the_oracle(
|
46
|
+
def obey_the_oracle(report: Report, data_path):
|
47
47
|
global __current_config_id
|
48
|
-
update_config(
|
48
|
+
update_config(report.oracle)
|
49
49
|
cfg = export_config()
|
50
|
-
__current_config_id =
|
50
|
+
__current_config_id = save_item(cfg, data_path)
|
51
51
|
|
52
52
|
|
53
|
-
def update_parameters(
|
53
|
+
def update_parameters(report: Report, data_path):
|
54
54
|
global __current_config_id
|
55
|
-
update_config(
|
55
|
+
update_config(report.parameters)
|
56
56
|
cfg = export_config()
|
57
|
-
__current_config_id =
|
57
|
+
__current_config_id = save_item(cfg, data_path)
|
58
58
|
|
59
59
|
|
60
60
|
def current_config(data_path):
|
61
61
|
global __current_config_id
|
62
62
|
if __current_config_id is None:
|
63
63
|
cfg = export_config()
|
64
|
-
__current_config_id =
|
64
|
+
__current_config_id = save_item(cfg, data_path)
|
65
65
|
return __current_config_id
|
66
66
|
|
67
67
|
|
qulab/executor/utils.py
CHANGED
@@ -37,7 +37,7 @@ def workflow_template(workflow: str, deps: list[str]) -> str:
|
|
37
37
|
import numpy as np
|
38
38
|
from loguru import logger
|
39
39
|
|
40
|
-
from qulab.typing import
|
40
|
+
from qulab.typing import Report
|
41
41
|
|
42
42
|
|
43
43
|
# 多长时间应该检查一次校准实验,单位是秒。
|
@@ -63,35 +63,35 @@ def calibrate():
|
|
63
63
|
return x, y
|
64
64
|
|
65
65
|
|
66
|
-
def analyze(
|
66
|
+
def analyze(report: Report, history: Report | None = None) -> Report:
|
67
67
|
\"\"\"
|
68
68
|
分析校准结果。
|
69
69
|
|
70
|
-
|
70
|
+
report: Report
|
71
71
|
本次校准实验的数据。
|
72
|
-
history:
|
72
|
+
history: Report | None
|
73
73
|
上次校准实验数据和分析结果,如果有的话。
|
74
74
|
\"\"\"
|
75
75
|
import random
|
76
76
|
|
77
|
-
# 这里添加你的分析过程,运行 calibrate 得到的数据,在
|
77
|
+
# 这里添加你的分析过程,运行 calibrate 得到的数据,在 report.data 里
|
78
78
|
# 你可以得到校准的结果,然后根据这个结果进行分析。
|
79
|
-
x, y =
|
79
|
+
x, y = report.data
|
80
80
|
|
81
81
|
# 完整校准后的状态有两种:OK 和 Bad,分别对应校准成功和校准失败。
|
82
82
|
# 校准失败是指出现坏数据,无法简单通过重新运行本次校准解决,需要
|
83
83
|
# 检查前置步骤。
|
84
|
-
|
84
|
+
report.state = random.choice(['OK', 'Bad'])
|
85
85
|
|
86
86
|
# 参数是一个字典,包含了本次校准得到的参数,后续会更新到config表中。
|
87
|
-
|
87
|
+
report.parameters = {{'gate.R.Q1.params.amp':1}}
|
88
88
|
|
89
89
|
# 其他信息可以是任何可序列化的内容,你可以将你想要记录的信息放在这里。
|
90
90
|
# 下次校准分析时,这些信息也会在 history 参数中一起传入,帮助你在下
|
91
91
|
# 次分析时对比参考。
|
92
|
-
|
92
|
+
report.other_infomation = {{}}
|
93
93
|
|
94
|
-
return
|
94
|
+
return report
|
95
95
|
|
96
96
|
|
97
97
|
def check():
|
@@ -111,33 +111,33 @@ def check():
|
|
111
111
|
return x, y
|
112
112
|
|
113
113
|
|
114
|
-
def check_analyze(
|
114
|
+
def check_analyze(report: Report, history: Report | None = None) -> Report:
|
115
115
|
\"\"\"
|
116
116
|
分析检查结果。
|
117
117
|
|
118
|
-
|
118
|
+
report: Report
|
119
119
|
本次检查实验的数据。
|
120
|
-
history:
|
120
|
+
history: Report | None
|
121
121
|
上次检查实验数据和分析结果,如果有的话。
|
122
122
|
\"\"\"
|
123
123
|
import random
|
124
124
|
|
125
|
-
# 这里添加你的分析过程,运行 check 得到的数据,在
|
125
|
+
# 这里添加你的分析过程,运行 check 得到的数据,在 report.data 里
|
126
126
|
# 你可以得到校准的结果,然后根据这个结果进行分析。
|
127
|
-
x, y =
|
127
|
+
x, y = report.data
|
128
128
|
|
129
129
|
# 状态有三种:Outdated, OK, Bad,分别对应过时、正常、坏数据。
|
130
130
|
# Outdated 是指数据过时,即参数漂了,需要重新校准。
|
131
131
|
# OK 是指数据正常,参数也没漂,不用重新校准。
|
132
132
|
# Bad 是指数据坏了,无法校准,需要检查前置步骤。
|
133
|
-
|
133
|
+
report.state = random.choice(['Outdated', 'OK', 'Bad'])
|
134
134
|
|
135
|
-
return
|
135
|
+
return report
|
136
136
|
|
137
137
|
|
138
|
-
def oracle(
|
139
|
-
history:
|
140
|
-
system_state: dict[str:str] | None = None) ->
|
138
|
+
def oracle(report: Report,
|
139
|
+
history: Report | None = None,
|
140
|
+
system_state: dict[str:str] | None = None) -> Report:
|
141
141
|
\"\"\"
|
142
142
|
谕示:指凭直觉或经验判断,改动某些配置,以期望下次校准成功。
|
143
143
|
|
@@ -145,31 +145,31 @@ def oracle(result: Result,
|
|
145
145
|
比如通常我们在死活测不到 rabi 或能谱时,会换一个 idle bias 再试试。这
|
146
146
|
里我们凭直觉设的那个 bias 值,就是一个谕示,可以通过 oracle 来设定。
|
147
147
|
|
148
|
-
该函数代入的参数
|
148
|
+
该函数代入的参数 report 是 analyze 函数的返回值。
|
149
149
|
\"\"\"
|
150
150
|
|
151
|
-
#
|
152
|
-
#
|
151
|
+
# report.oracle['Q0.bias'] = 0.1
|
152
|
+
# report.oracle['Q1.bias'] = -0.03
|
153
153
|
|
154
|
-
return
|
154
|
+
return report
|
155
155
|
"""
|
156
156
|
|
157
157
|
|
158
158
|
def debug_analyze(
|
159
|
-
|
159
|
+
report_index: int,
|
160
160
|
code_path: str | Path = get_config_value('code', Path),
|
161
161
|
data_path: str | Path = get_config_value('data', Path),
|
162
162
|
) -> None:
|
163
|
-
from .storage import
|
163
|
+
from .storage import get_report_by_index
|
164
164
|
|
165
|
-
|
166
|
-
if
|
167
|
-
raise ValueError(f'Invalid
|
168
|
-
workflow =
|
165
|
+
report = get_report_by_index(report_index, data_path)
|
166
|
+
if report is None:
|
167
|
+
raise ValueError(f'Invalid report index: {report_index}')
|
168
|
+
workflow = report.workflow
|
169
169
|
wf = load_workflow(workflow, code_path)
|
170
170
|
if wf is None:
|
171
171
|
raise ValueError(f'Invalid workflow: {workflow}')
|
172
|
-
|
172
|
+
report = wf.analyze(report, report.previous)
|
173
173
|
if hasattr(wf, 'plot'):
|
174
|
-
wf.plot(
|
175
|
-
return
|
174
|
+
wf.plot(report)
|
175
|
+
return report
|
qulab/fun.cpython-310-darwin.so
CHANGED
Binary file
|
qulab/typing.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
from .executor.storage import
|
1
|
+
from .executor.storage import Report
|
2
2
|
from .scan.record import Record
|
qulab/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "2.7.
|
1
|
+
__version__ = "2.7.10"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|