QuLab 2.0.9__cp310-cp310-win_amd64.whl → 2.1.0__cp310-cp310-win_amd64.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.0.9.dist-info → QuLab-2.1.0.dist-info}/METADATA +1 -1
- {QuLab-2.0.9.dist-info → QuLab-2.1.0.dist-info}/RECORD +10 -10
- qulab/fun.cp310-win_amd64.pyd +0 -0
- qulab/scan/recorder.py +115 -34
- qulab/scan/scan.py +126 -84
- qulab/version.py +1 -1
- {QuLab-2.0.9.dist-info → QuLab-2.1.0.dist-info}/LICENSE +0 -0
- {QuLab-2.0.9.dist-info → QuLab-2.1.0.dist-info}/WHEEL +0 -0
- {QuLab-2.0.9.dist-info → QuLab-2.1.0.dist-info}/entry_points.txt +0 -0
- {QuLab-2.0.9.dist-info → QuLab-2.1.0.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
qulab/__init__.py,sha256=8zLGg-DfQhnDl2Ky0n-zXpN-8e-g7iR0AcaI4l4Vvpk,32
|
|
2
2
|
qulab/__main__.py,sha256=XN2wrhlmEkTIPq_ZeSaO8rWXfYgD2Czkm9DVFVoCw_U,515
|
|
3
|
-
qulab/fun.cp310-win_amd64.pyd,sha256=
|
|
4
|
-
qulab/version.py,sha256=
|
|
3
|
+
qulab/fun.cp310-win_amd64.pyd,sha256=TJx4S6iII5ytbEyEuzm5Wm6BWLK5wDo0e3cqzBsC6nc,31232
|
|
4
|
+
qulab/version.py,sha256=5VFOC9N5P61WNNAC14BfsqZmQ2X-yL6b-UnG_oixpYM,21
|
|
5
5
|
qulab/monitor/__init__.py,sha256=xEVDkJF8issrsDeLqQmDsvtRmrf-UiViFcGTWuzdlFU,43
|
|
6
6
|
qulab/monitor/__main__.py,sha256=k2H1H5Zf9LLXTDLISJkbikLH-z0f1e5i5i6wXXYPOrE,105
|
|
7
7
|
qulab/monitor/config.py,sha256=y_5StMkdrbZO1ziyKBrvIkB7Jclp9RCPK1QbsOhCxnY,785
|
|
@@ -18,8 +18,8 @@ qulab/scan/expression.py,sha256=vwUM9E0OFQal4bljlUtLR3NJu4zGRyuWYrdyZSs3QTU,1619
|
|
|
18
18
|
qulab/scan/models.py,sha256=TkiVHF_fUZzYHs4MsCTRh391thpf4Ozd3R_LAU0Gxkg,17657
|
|
19
19
|
qulab/scan/optimize.py,sha256=MlT4y422CnP961IR384UKryyZh8riNvrPSd2z_MXLEg,2356
|
|
20
20
|
qulab/scan/query_record.py,sha256=rpw4U3NjLzlv9QMwKdCvEUGHjzPF8u1UpodfLW8aoTY,11853
|
|
21
|
-
qulab/scan/recorder.py,sha256=
|
|
22
|
-
qulab/scan/scan.py,sha256=
|
|
21
|
+
qulab/scan/recorder.py,sha256=cTKYP6vQzOXl9E5bj50qkxJPOh1virpJRW21pi53SaY,26426
|
|
22
|
+
qulab/scan/scan.py,sha256=2Ekfj3c7O91FR4eFSAb0G0wm8g9_f3xXfH7tIVnqrDc,30657
|
|
23
23
|
qulab/scan/server.py,sha256=zDZfG6bOB3EUubfByQMq0BSQ9C6IV_Av0tDinzgpGjQ,2950
|
|
24
24
|
qulab/scan/utils.py,sha256=XM-eKL5Xkm0hihhGS7Kq4g654Ye7n7TcU_f95gxtXq8,2634
|
|
25
25
|
qulab/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -77,9 +77,9 @@ qulab/visualization/plot_layout.py,sha256=yAnMONOms7_szCdng-8wPpUMPis5UnbaNNzV4K
|
|
|
77
77
|
qulab/visualization/plot_seq.py,sha256=h9D0Yl_yO64IwlvBgzMu9EBKr9gg6y8QE55gu2PfTns,2783
|
|
78
78
|
qulab/visualization/qdat.py,sha256=HubXFu4nfcA7iUzghJGle1C86G6221hicLR0b-GqhKQ,5887
|
|
79
79
|
qulab/visualization/widgets.py,sha256=HcYwdhDtLreJiYaZuN3LfofjJmZcLwjMfP5aasebgDo,3266
|
|
80
|
-
QuLab-2.0.
|
|
81
|
-
QuLab-2.0.
|
|
82
|
-
QuLab-2.0.
|
|
83
|
-
QuLab-2.0.
|
|
84
|
-
QuLab-2.0.
|
|
85
|
-
QuLab-2.0.
|
|
80
|
+
QuLab-2.1.0.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
|
|
81
|
+
QuLab-2.1.0.dist-info/METADATA,sha256=w7Kk5WbBivHCA5jWGexSPxsiwY_PBVr85_-wrXz3BW0,3609
|
|
82
|
+
QuLab-2.1.0.dist-info/WHEEL,sha256=lO6CqtLHCAi38X3Es1a4R1lAjZFvN010IMRCFo2S7Mc,102
|
|
83
|
+
QuLab-2.1.0.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
|
|
84
|
+
QuLab-2.1.0.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
|
|
85
|
+
QuLab-2.1.0.dist-info/RECORD,,
|
qulab/fun.cp310-win_amd64.pyd
CHANGED
|
Binary file
|
qulab/scan/recorder.py
CHANGED
|
@@ -69,14 +69,14 @@ class BufferList():
|
|
|
69
69
|
self._list = []
|
|
70
70
|
self.lu = ()
|
|
71
71
|
self.rd = ()
|
|
72
|
-
self.inner_shape =
|
|
72
|
+
self.inner_shape = ()
|
|
73
73
|
self.file = file
|
|
74
74
|
self._slice = slice
|
|
75
75
|
self._lock = Lock()
|
|
76
|
-
self.
|
|
76
|
+
self._data_id = None
|
|
77
77
|
|
|
78
78
|
def __repr__(self):
|
|
79
|
-
return f"<BufferList: lu={self.lu}, rd={self.rd}, slice={self._slice}>"
|
|
79
|
+
return f"<BufferList: shape={self.shape}, lu={self.lu}, rd={self.rd}, slice={self._slice}>"
|
|
80
80
|
|
|
81
81
|
def __getstate__(self):
|
|
82
82
|
self.flush()
|
|
@@ -99,11 +99,12 @@ class BufferList():
|
|
|
99
99
|
self._list = []
|
|
100
100
|
self._slice = None
|
|
101
101
|
self._lock = Lock()
|
|
102
|
-
self.
|
|
102
|
+
self._data_id = None
|
|
103
103
|
|
|
104
104
|
@property
|
|
105
105
|
def shape(self):
|
|
106
|
-
return tuple([i - j
|
|
106
|
+
return tuple([i - j
|
|
107
|
+
for i, j in zip(self.rd, self.lu)]) + self.inner_shape
|
|
107
108
|
|
|
108
109
|
def flush(self):
|
|
109
110
|
if not self._list:
|
|
@@ -143,11 +144,27 @@ class BufferList():
|
|
|
143
144
|
break
|
|
144
145
|
|
|
145
146
|
def iter(self):
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
147
|
+
if self._data_id is None:
|
|
148
|
+
for pos, value in itertools.chain(self._iter_file(), self._list):
|
|
149
|
+
if not self._slice:
|
|
150
|
+
yield pos, value
|
|
151
|
+
elif all(
|
|
152
|
+
[index_in_slice(s, i) for s, i in zip(self._slice, pos)]):
|
|
153
|
+
if self.inner_shape:
|
|
154
|
+
yield pos, value[self._slice[len(pos):]]
|
|
155
|
+
else:
|
|
156
|
+
yield pos, value
|
|
157
|
+
else:
|
|
158
|
+
server, record_id, key = self._data_id
|
|
159
|
+
with ZMQContextManager(zmq.DEALER, connect=server) as socket:
|
|
160
|
+
socket.send_pyobj({
|
|
161
|
+
'method': 'bufferlist_slice',
|
|
162
|
+
'record_id': record_id,
|
|
163
|
+
'key': key,
|
|
164
|
+
'slice': self._slice
|
|
165
|
+
})
|
|
166
|
+
ret = socket.recv_pyobj()
|
|
167
|
+
yield from ret
|
|
151
168
|
|
|
152
169
|
def value(self):
|
|
153
170
|
d = []
|
|
@@ -170,47 +187,111 @@ class BufferList():
|
|
|
170
187
|
|
|
171
188
|
def array(self):
|
|
172
189
|
pos, data = self.items()
|
|
173
|
-
|
|
190
|
+
if self._slice:
|
|
191
|
+
pos = np.asarray(pos)
|
|
192
|
+
lu = tuple(np.min(pos, axis=0))
|
|
193
|
+
rd = tuple(np.max(pos, axis=0) + 1)
|
|
194
|
+
pos = np.asarray(pos) - np.asarray(lu)
|
|
195
|
+
shape = []
|
|
196
|
+
for k, (s, i, j) in enumerate(zip(self._slice, rd, lu)):
|
|
197
|
+
if s.step is not None:
|
|
198
|
+
pos[:, k] = pos[:, k] / s.step
|
|
199
|
+
shape.append(round(np.ceil((i - j) / s.step)))
|
|
200
|
+
else:
|
|
201
|
+
shape.append(i - j)
|
|
202
|
+
shape = tuple(shape)
|
|
203
|
+
else:
|
|
204
|
+
shape = tuple([i - j for i, j in zip(self.rd, self.lu)])
|
|
205
|
+
pos = np.asarray(pos) - np.asarray(self.lu)
|
|
174
206
|
data = np.asarray(data)
|
|
175
207
|
inner_shape = data.shape[1:]
|
|
176
|
-
x = np.full(
|
|
208
|
+
x = np.full(shape + inner_shape, np.nan, dtype=data[0].dtype)
|
|
177
209
|
x.__setitem__(tuple(pos.T), data)
|
|
178
210
|
return x
|
|
179
211
|
|
|
180
212
|
def _full_slice(self, slice_tuple: slice
|
|
181
213
|
| tuple[slice | int | EllipsisType, ...]):
|
|
214
|
+
ndim = len(self.lu)
|
|
215
|
+
if self.inner_shape:
|
|
216
|
+
ndim += len(self.inner_shape)
|
|
217
|
+
|
|
182
218
|
if isinstance(slice_tuple, slice):
|
|
183
|
-
slice_tuple = (
|
|
184
|
-
|
|
219
|
+
slice_tuple = (
|
|
220
|
+
slice_tuple, ) + (slice(0, sys.maxsize, 1), ) * (ndim - 1)
|
|
185
221
|
if slice_tuple is Ellipsis:
|
|
186
|
-
slice_tuple = (slice(0, sys.maxsize, 1), ) *
|
|
222
|
+
slice_tuple = (slice(0, sys.maxsize, 1), ) * ndim
|
|
187
223
|
else:
|
|
188
|
-
head, tail =
|
|
224
|
+
head, tail = (), ()
|
|
189
225
|
for i, s in enumerate(slice_tuple):
|
|
190
226
|
if s is Ellipsis:
|
|
191
227
|
head = slice_tuple[:i]
|
|
192
228
|
tail = slice_tuple[i + 1:]
|
|
193
229
|
break
|
|
194
|
-
|
|
195
|
-
|
|
230
|
+
else:
|
|
231
|
+
head = slice_tuple
|
|
232
|
+
tail = ()
|
|
233
|
+
slice_tuple = head + (slice(
|
|
234
|
+
0, sys.maxsize, 1), ) * (ndim - len(head) - len(tail)) + tail
|
|
196
235
|
slice_list = []
|
|
197
|
-
|
|
236
|
+
contract = []
|
|
237
|
+
reversed = []
|
|
238
|
+
for i, s in enumerate(slice_tuple):
|
|
198
239
|
if isinstance(s, int):
|
|
199
|
-
|
|
240
|
+
if s >= 0:
|
|
241
|
+
slice_list.append(slice(s, s + 1, 1))
|
|
242
|
+
elif i < len(self.lu):
|
|
243
|
+
s = self.rd[i] + s
|
|
244
|
+
slice_list.append(slice(s, s + 1, 1))
|
|
245
|
+
else:
|
|
246
|
+
slice_list.append(slice(s, s - 1, -1))
|
|
247
|
+
contract.append(i)
|
|
200
248
|
else:
|
|
201
249
|
start, stop, step = s.start, s.stop, s.step
|
|
250
|
+
if step is None:
|
|
251
|
+
step = 1
|
|
252
|
+
if step < 0 and i < len(self.lu):
|
|
253
|
+
step = -step
|
|
254
|
+
reversed.append(i)
|
|
255
|
+
if start is None and stop is None:
|
|
256
|
+
start, stop = 0, sys.maxsize
|
|
257
|
+
elif start is None:
|
|
258
|
+
start, stop = self.lu[i], sys.maxsize
|
|
259
|
+
elif stop is None:
|
|
260
|
+
start, stop = 0, start + self.lu[i]
|
|
261
|
+
else:
|
|
262
|
+
start, stop = stop + self.lu[i] + 1, start + self.lu[
|
|
263
|
+
i] + 1
|
|
264
|
+
|
|
202
265
|
if start is None:
|
|
203
266
|
start = 0
|
|
267
|
+
elif start < 0 and i < len(self.lu):
|
|
268
|
+
start = self.rd[i] + start
|
|
204
269
|
if step is None:
|
|
205
270
|
step = 1
|
|
206
271
|
if stop is None:
|
|
207
272
|
stop = sys.maxsize
|
|
273
|
+
elif stop < 0 and i < len(self.lu):
|
|
274
|
+
stop = self.rd[i] + stop
|
|
275
|
+
|
|
208
276
|
slice_list.append(slice(start, stop, step))
|
|
209
|
-
return tuple(slice_list)
|
|
277
|
+
return tuple(slice_list), contract, reversed
|
|
210
278
|
|
|
211
279
|
def __getitem__(self, slice_tuple: slice | EllipsisType
|
|
212
280
|
| tuple[slice | int | EllipsisType, ...]):
|
|
213
|
-
|
|
281
|
+
self._slice, contract, reversed = self._full_slice(slice_tuple)
|
|
282
|
+
ret = self.array()
|
|
283
|
+
slices = []
|
|
284
|
+
for i, s in enumerate(self._slice):
|
|
285
|
+
if i in contract:
|
|
286
|
+
slices.append(0)
|
|
287
|
+
elif isinstance(s, slice):
|
|
288
|
+
if i in reversed:
|
|
289
|
+
slices.append(slice(None, None, -1))
|
|
290
|
+
else:
|
|
291
|
+
slices.append(slice(None, None, 1))
|
|
292
|
+
ret = ret.__getitem__(tuple(slices))
|
|
293
|
+
self._slice = None
|
|
294
|
+
return ret
|
|
214
295
|
|
|
215
296
|
|
|
216
297
|
class Record():
|
|
@@ -310,9 +391,9 @@ class Record():
|
|
|
310
391
|
self.flush()
|
|
311
392
|
|
|
312
393
|
def __getitem__(self, key):
|
|
313
|
-
return self.get(key)
|
|
394
|
+
return self.get(key, buffer_to_array=True)
|
|
314
395
|
|
|
315
|
-
def get(self, key, default=_notgiven, buffer_to_array=
|
|
396
|
+
def get(self, key, default=_notgiven, buffer_to_array=False, slice=None):
|
|
316
397
|
if self.is_remote_record():
|
|
317
398
|
with ZMQContextManager(zmq.DEALER,
|
|
318
399
|
connect=self.database) as socket:
|
|
@@ -323,19 +404,19 @@ class Record():
|
|
|
323
404
|
})
|
|
324
405
|
ret = socket.recv_pyobj()
|
|
325
406
|
if isinstance(ret, BufferList):
|
|
326
|
-
socket.send_pyobj({
|
|
327
|
-
'method': 'bufferlist_slice',
|
|
328
|
-
'record_id': self.id,
|
|
329
|
-
'key': key,
|
|
330
|
-
'slice': slice
|
|
331
|
-
})
|
|
332
|
-
lst = socket.recv_pyobj()
|
|
333
|
-
ret._list = lst
|
|
334
|
-
ret._slice = slice
|
|
335
407
|
if buffer_to_array:
|
|
408
|
+
socket.send_pyobj({
|
|
409
|
+
'method': 'bufferlist_slice',
|
|
410
|
+
'record_id': self.id,
|
|
411
|
+
'key': key,
|
|
412
|
+
'slice': slice
|
|
413
|
+
})
|
|
414
|
+
lst = socket.recv_pyobj()
|
|
415
|
+
ret._list = lst
|
|
416
|
+
ret._slice = slice
|
|
336
417
|
return ret.array()
|
|
337
418
|
else:
|
|
338
|
-
ret.
|
|
419
|
+
ret._data_id = self.database, self.id, key
|
|
339
420
|
return ret
|
|
340
421
|
else:
|
|
341
422
|
return ret
|
qulab/scan/scan.py
CHANGED
|
@@ -8,6 +8,7 @@ import re
|
|
|
8
8
|
import sys
|
|
9
9
|
import uuid
|
|
10
10
|
import warnings
|
|
11
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
11
12
|
from graphlib import TopologicalSorter
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
from types import MethodType
|
|
@@ -157,6 +158,11 @@ class Promise():
|
|
|
157
158
|
return Promise(self.task, None, attr)
|
|
158
159
|
|
|
159
160
|
|
|
161
|
+
def _run_function_in_process(buf):
|
|
162
|
+
func, args, kwds = dill.loads(buf)
|
|
163
|
+
return func(*args, **kwds)
|
|
164
|
+
|
|
165
|
+
|
|
160
166
|
class Scan():
|
|
161
167
|
|
|
162
168
|
def __new__(cls, *args, mixin=None, **kwds):
|
|
@@ -176,6 +182,8 @@ class Scan():
|
|
|
176
182
|
database: str | Path
|
|
177
183
|
| None = f'tcp://127.0.0.1:{default_record_port}',
|
|
178
184
|
dump_globals: bool = False,
|
|
185
|
+
max_workers: int = 4,
|
|
186
|
+
max_promise: int = 100,
|
|
179
187
|
mixin=None):
|
|
180
188
|
self.id = task_uuid()
|
|
181
189
|
self.record = None
|
|
@@ -207,23 +215,21 @@ class Scan():
|
|
|
207
215
|
self._variables = {}
|
|
208
216
|
self._main_task = None
|
|
209
217
|
self._sock = None
|
|
210
|
-
self._sem = asyncio.Semaphore(
|
|
218
|
+
self._sem = asyncio.Semaphore(max_promise + 1)
|
|
211
219
|
self._bar: dict[int, tqdm] = {}
|
|
212
220
|
self._hide_pattern_re = re.compile('|'.join(self.description['hiden']))
|
|
213
|
-
self.
|
|
214
|
-
self.
|
|
221
|
+
self._msg_queue = asyncio.Queue()
|
|
222
|
+
self._prm_queue = asyncio.Queue()
|
|
215
223
|
self._single_step = True
|
|
224
|
+
self._max_workers = max_workers
|
|
225
|
+
self._max_promise = max_promise
|
|
226
|
+
self._executors = ProcessPoolExecutor(max_workers=max_workers)
|
|
216
227
|
|
|
217
228
|
def __del__(self):
|
|
218
229
|
try:
|
|
219
230
|
self._main_task.cancel()
|
|
220
231
|
except:
|
|
221
232
|
pass
|
|
222
|
-
for task in self._task_pool:
|
|
223
|
-
try:
|
|
224
|
-
task.cancel()
|
|
225
|
-
except:
|
|
226
|
-
pass
|
|
227
233
|
|
|
228
234
|
def __getstate__(self) -> dict:
|
|
229
235
|
state = self.__dict__.copy()
|
|
@@ -231,9 +237,10 @@ class Scan():
|
|
|
231
237
|
del state['_sock']
|
|
232
238
|
del state['_main_task']
|
|
233
239
|
del state['_bar']
|
|
234
|
-
del state['
|
|
235
|
-
del state['
|
|
240
|
+
del state['_msg_queue']
|
|
241
|
+
del state['_prm_queue']
|
|
236
242
|
del state['_sem']
|
|
243
|
+
del state['_executors']
|
|
237
244
|
return state
|
|
238
245
|
|
|
239
246
|
def __setstate__(self, state: dict) -> None:
|
|
@@ -242,12 +249,20 @@ class Scan():
|
|
|
242
249
|
self._sock = None
|
|
243
250
|
self._main_task = None
|
|
244
251
|
self._bar = {}
|
|
245
|
-
self.
|
|
246
|
-
self.
|
|
247
|
-
self._sem = asyncio.Semaphore(
|
|
252
|
+
self._prm_queue = asyncio.Queue()
|
|
253
|
+
self._msg_queue = asyncio.Queue()
|
|
254
|
+
self._sem = asyncio.Semaphore(self._max_promise + 1)
|
|
255
|
+
self._executors = ProcessPoolExecutor(max_workers=self._max_workers)
|
|
248
256
|
for opt in self.description['optimizers'].values():
|
|
249
257
|
opt.scanner = self
|
|
250
258
|
|
|
259
|
+
def __del__(self):
|
|
260
|
+
try:
|
|
261
|
+
self._main_task.cancel()
|
|
262
|
+
except:
|
|
263
|
+
pass
|
|
264
|
+
self._executors.shutdown()
|
|
265
|
+
|
|
251
266
|
@property
|
|
252
267
|
def current_level(self):
|
|
253
268
|
return self._current_level
|
|
@@ -256,8 +271,8 @@ class Scan():
|
|
|
256
271
|
def variables(self) -> dict[str, Any]:
|
|
257
272
|
return self._variables
|
|
258
273
|
|
|
259
|
-
async def
|
|
260
|
-
|
|
274
|
+
async def _emit(self, current_level, step, position, variables: dict[str,
|
|
275
|
+
Any]):
|
|
261
276
|
for key, value in list(variables.items()):
|
|
262
277
|
if inspect.isawaitable(value) and not self.hiden(key):
|
|
263
278
|
variables[key] = await value
|
|
@@ -280,6 +295,11 @@ class Scan():
|
|
|
280
295
|
for k, v in variables.items() if not self.hiden(k)
|
|
281
296
|
})
|
|
282
297
|
|
|
298
|
+
def emit(self, current_level, step, position, variables: dict[str, Any]):
|
|
299
|
+
self._msg_queue.put_nowait(
|
|
300
|
+
asyncio.create_task(
|
|
301
|
+
self._emit(current_level, step, position, variables.copy())))
|
|
302
|
+
|
|
283
303
|
def hide(self, name: str):
|
|
284
304
|
self.description['hiden'].append(name)
|
|
285
305
|
self._hide_pattern_re = re.compile('|'.join(self.description['hiden']))
|
|
@@ -289,11 +309,11 @@ class Scan():
|
|
|
289
309
|
|
|
290
310
|
async def _filter(self, variables: dict[str, Any], level: int = 0):
|
|
291
311
|
try:
|
|
292
|
-
return all([
|
|
293
|
-
|
|
312
|
+
return all(await asyncio.gather(*[
|
|
313
|
+
call_function(fun, variables) for fun in itertools.chain(
|
|
294
314
|
self.description['filters'].get(level, []),
|
|
295
315
|
self.description['filters'].get(-1, []))
|
|
296
|
-
])
|
|
316
|
+
]))
|
|
297
317
|
except:
|
|
298
318
|
return True
|
|
299
319
|
|
|
@@ -432,11 +452,15 @@ class Scan():
|
|
|
432
452
|
|
|
433
453
|
async def _update_progress(self):
|
|
434
454
|
while True:
|
|
435
|
-
task = await self.
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
455
|
+
task = await self._prm_queue.get()
|
|
456
|
+
await task
|
|
457
|
+
self._prm_queue.task_done()
|
|
458
|
+
|
|
459
|
+
async def _send_msg(self):
|
|
460
|
+
while True:
|
|
461
|
+
task = await self._msg_queue.get()
|
|
462
|
+
await task
|
|
463
|
+
self._msg_queue.task_done()
|
|
440
464
|
|
|
441
465
|
async def run(self):
|
|
442
466
|
assymbly(self.description)
|
|
@@ -452,44 +476,41 @@ class Scan():
|
|
|
452
476
|
await self._run()
|
|
453
477
|
|
|
454
478
|
async def _run(self):
|
|
455
|
-
|
|
456
|
-
self.
|
|
479
|
+
send_msg = asyncio.create_task(self._send_msg())
|
|
480
|
+
update_progress_task = asyncio.create_task(self._update_progress())
|
|
481
|
+
|
|
457
482
|
self._variables = {'self': self}
|
|
458
|
-
|
|
483
|
+
|
|
484
|
+
await update_variables(self._variables, self.description['consts'],
|
|
485
|
+
self.description['setters'])
|
|
459
486
|
for level, total in self.description['total'].items():
|
|
460
487
|
if total == np.inf:
|
|
461
488
|
total = None
|
|
462
489
|
self._bar[level] = tqdm(total=total)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
self.variables[name])
|
|
471
|
-
if inspect.isawaitable(coro):
|
|
472
|
-
await coro
|
|
490
|
+
|
|
491
|
+
updates = await call_many_functions(
|
|
492
|
+
self.description['order'].get(-1, []),
|
|
493
|
+
self.description['functions'], self.variables)
|
|
494
|
+
await update_variables(self.variables, updates,
|
|
495
|
+
self.description['setters'])
|
|
496
|
+
|
|
473
497
|
self.record = await self.create_record()
|
|
474
498
|
await self.work()
|
|
475
499
|
for level, bar in self._bar.items():
|
|
476
500
|
bar.close()
|
|
477
501
|
|
|
478
|
-
while not self._task_queue.empty():
|
|
479
|
-
evt = self._task_queue.get_nowait()
|
|
480
|
-
if isinstance(evt, asyncio.Event):
|
|
481
|
-
evt.set()
|
|
482
|
-
elif inspect.isawaitable(evt):
|
|
483
|
-
await evt
|
|
484
502
|
if self._single_step:
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
503
|
+
self.variables.update(await call_many_functions(
|
|
504
|
+
self.description['order'].get(-1, []),
|
|
505
|
+
self.description['getters'], self.variables))
|
|
506
|
+
|
|
507
|
+
self.emit(0, 0, 0, self.variables)
|
|
508
|
+
self.emit(-1, 0, 0, {})
|
|
509
|
+
|
|
510
|
+
await self._prm_queue.join()
|
|
511
|
+
update_progress_task.cancel()
|
|
512
|
+
await self._msg_queue.join()
|
|
513
|
+
send_msg.cancel()
|
|
493
514
|
return self.variables
|
|
494
515
|
|
|
495
516
|
async def done(self):
|
|
@@ -536,8 +557,8 @@ class Scan():
|
|
|
536
557
|
return
|
|
537
558
|
step = 0
|
|
538
559
|
position = 0
|
|
539
|
-
self.
|
|
540
|
-
self.
|
|
560
|
+
self._prm_queue.put_nowait(self._reset_progress_bar(
|
|
561
|
+
self.current_level))
|
|
541
562
|
async for variables in _iter_level(
|
|
542
563
|
self.variables,
|
|
543
564
|
self.description['loops'].get(self.current_level, []),
|
|
@@ -548,23 +569,18 @@ class Scan():
|
|
|
548
569
|
if await self._filter(variables, self.current_level - 1):
|
|
549
570
|
yield variables
|
|
550
571
|
self._single_step = False
|
|
551
|
-
|
|
552
|
-
self.emit(self.current_level - 1, step, position,
|
|
553
|
-
variables.copy()))
|
|
572
|
+
self.emit(self.current_level - 1, step, position, variables)
|
|
554
573
|
step += 1
|
|
555
574
|
position += 1
|
|
556
575
|
self._current_level -= 1
|
|
557
|
-
self.
|
|
576
|
+
self._prm_queue.put_nowait(
|
|
558
577
|
self._update_progress_bar(self.current_level, 1))
|
|
559
578
|
if self.current_level == 0:
|
|
560
|
-
|
|
579
|
+
self.emit(self.current_level - 1, 0, 0, {})
|
|
561
580
|
for name, value in self.variables.items():
|
|
562
581
|
if inspect.isawaitable(value):
|
|
563
582
|
self.variables[name] = await value
|
|
564
|
-
|
|
565
|
-
task = self._task_queue.get_nowait()
|
|
566
|
-
if inspect.isawaitable(task):
|
|
567
|
-
await task
|
|
583
|
+
await self._prm_queue.join()
|
|
568
584
|
|
|
569
585
|
async def work(self, **kwds):
|
|
570
586
|
if self.current_level in self.description['actions']:
|
|
@@ -589,7 +605,8 @@ class Scan():
|
|
|
589
605
|
"""
|
|
590
606
|
self.description['actions'][level] = action
|
|
591
607
|
|
|
592
|
-
async def promise(self, awaitable: Awaitable
|
|
608
|
+
async def promise(self, awaitable: Awaitable | Callable, *args,
|
|
609
|
+
**kwds) -> Promise:
|
|
593
610
|
"""
|
|
594
611
|
Promise to calculate asynchronous function and return the result in future.
|
|
595
612
|
|
|
@@ -602,8 +619,19 @@ class Scan():
|
|
|
602
619
|
if inspect.isawaitable(awaitable):
|
|
603
620
|
async with self._sem:
|
|
604
621
|
task = asyncio.create_task(self._await(awaitable))
|
|
605
|
-
self.
|
|
622
|
+
self._prm_queue.put_nowait(task)
|
|
606
623
|
return Promise(task)
|
|
624
|
+
elif inspect.iscoroutinefunction(awaitable):
|
|
625
|
+
return await self.promise(awaitable(*args, **kwds))
|
|
626
|
+
elif callable(awaitable):
|
|
627
|
+
try:
|
|
628
|
+
buf = dill.dumps((awaitable, args, kwds))
|
|
629
|
+
task = asyncio.get_running_loop().run_in_executor(
|
|
630
|
+
self._executors, _run_function_in_process, buf)
|
|
631
|
+
self._prm_queue.put_nowait(task)
|
|
632
|
+
return Promise(task)
|
|
633
|
+
except:
|
|
634
|
+
return awaitable(*args, **kwds)
|
|
607
635
|
else:
|
|
608
636
|
return awaitable
|
|
609
637
|
|
|
@@ -785,13 +813,17 @@ def assymbly(description):
|
|
|
785
813
|
return description
|
|
786
814
|
|
|
787
815
|
|
|
788
|
-
async def
|
|
816
|
+
async def update_variables(variables: dict[str, Any], updates: dict[str, Any],
|
|
817
|
+
setters: dict[str, Callable]):
|
|
818
|
+
coros = []
|
|
789
819
|
for name, value in updates.items():
|
|
790
820
|
if name in setters:
|
|
791
821
|
coro = setters[name](value)
|
|
792
822
|
if inspect.isawaitable(coro):
|
|
793
|
-
|
|
823
|
+
coros.append(coro)
|
|
794
824
|
variables[name] = value
|
|
825
|
+
if coros:
|
|
826
|
+
await asyncio.gather(*coros)
|
|
795
827
|
|
|
796
828
|
|
|
797
829
|
async def _iter_level(variables,
|
|
@@ -824,31 +856,23 @@ async def _iter_level(variables,
|
|
|
824
856
|
maxiter = min(maxiter, opt_cfg.maxiter)
|
|
825
857
|
|
|
826
858
|
async for args in async_zip(*iters_d.values(), range(maxiter)):
|
|
827
|
-
await
|
|
828
|
-
|
|
859
|
+
await update_variables(variables, dict(zip(iters_d.keys(), args[:-1])),
|
|
860
|
+
setters)
|
|
829
861
|
for name, opt in opts.items():
|
|
830
862
|
args = opt.ask()
|
|
831
863
|
opt_cfg = optimizers[name]
|
|
832
|
-
await
|
|
864
|
+
await update_variables(variables, {
|
|
833
865
|
n: v
|
|
834
866
|
for n, v in zip(opt_cfg.dimensions.keys(), args)
|
|
835
867
|
}, setters)
|
|
836
868
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
await _update_variables(variables, {
|
|
841
|
-
name:
|
|
842
|
-
await call_function(functions[name], variables)
|
|
843
|
-
}, setters)
|
|
869
|
+
await update_variables(
|
|
870
|
+
variables, await call_many_functions(order, functions, variables),
|
|
871
|
+
setters)
|
|
844
872
|
|
|
845
873
|
yield variables
|
|
846
874
|
|
|
847
|
-
|
|
848
|
-
for name in group:
|
|
849
|
-
if name in getters:
|
|
850
|
-
variables[name] = await call_function(
|
|
851
|
-
getters[name], variables)
|
|
875
|
+
variables.update(await call_many_functions(order, getters, variables))
|
|
852
876
|
|
|
853
877
|
for name, opt in opts.items():
|
|
854
878
|
opt_cfg = optimizers[name]
|
|
@@ -866,10 +890,28 @@ async def _iter_level(variables,
|
|
|
866
890
|
for name, opt in opts.items():
|
|
867
891
|
opt_cfg = optimizers[name]
|
|
868
892
|
result = opt.get_result()
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
893
|
+
await update_variables(
|
|
894
|
+
variables, {
|
|
895
|
+
name: value
|
|
896
|
+
for name, value in zip(opt_cfg.dimensions.keys(), result.x)
|
|
897
|
+
}, setters)
|
|
873
898
|
variables[name] = result.fun
|
|
874
899
|
if opts:
|
|
875
900
|
yield variables
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
async def call_many_functions(order: list[list[str]],
|
|
904
|
+
functions: dict[str, Callable],
|
|
905
|
+
variables: dict[str, Any]) -> dict[str, Any]:
|
|
906
|
+
ret = {}
|
|
907
|
+
for group in order:
|
|
908
|
+
waited = []
|
|
909
|
+
coros = []
|
|
910
|
+
for name in group:
|
|
911
|
+
if name in functions:
|
|
912
|
+
waited.append(name)
|
|
913
|
+
coros.append(call_function(functions[name], variables | ret))
|
|
914
|
+
if coros:
|
|
915
|
+
results = await asyncio.gather(*coros)
|
|
916
|
+
ret.update(dict(zip(waited, results)))
|
|
917
|
+
return ret
|
qulab/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.0
|
|
1
|
+
__version__ = "2.1.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|