QuLab 2.0.8__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.8.dist-info → QuLab-2.1.0.dist-info}/METADATA +1 -1
- {QuLab-2.0.8.dist-info → QuLab-2.1.0.dist-info}/RECORD +10 -10
- qulab/fun.cp310-win_amd64.pyd +0 -0
- qulab/scan/recorder.py +132 -42
- qulab/scan/scan.py +132 -89
- qulab/version.py +1 -1
- {QuLab-2.0.8.dist-info → QuLab-2.1.0.dist-info}/LICENSE +0 -0
- {QuLab-2.0.8.dist-info → QuLab-2.1.0.dist-info}/WHEEL +0 -0
- {QuLab-2.0.8.dist-info → QuLab-2.1.0.dist-info}/entry_points.txt +0 -0
- {QuLab-2.0.8.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,52 +187,118 @@ 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():
|
|
217
298
|
|
|
218
299
|
def __init__(self, id, database, description=None):
|
|
300
|
+
from .scan import OptimizeSpace
|
|
301
|
+
|
|
219
302
|
self.id = id
|
|
220
303
|
self.database = database
|
|
221
304
|
self.description = description
|
|
@@ -236,22 +319,29 @@ class Record():
|
|
|
236
319
|
self.dims[name] = ()
|
|
237
320
|
for level, range_list in self.description['loops'].items():
|
|
238
321
|
for name, iterable in range_list:
|
|
239
|
-
if isinstance(iterable,
|
|
322
|
+
if isinstance(iterable, OptimizeSpace):
|
|
323
|
+
self.dims[name] = tuple(range(level + 1))
|
|
324
|
+
continue
|
|
325
|
+
elif isinstance(iterable, (np.ndarray, list, tuple, range)):
|
|
240
326
|
self._items[name] = iterable
|
|
241
327
|
self.independent_variables[name] = iterable
|
|
242
|
-
|
|
328
|
+
self.dims[name] = (level, )
|
|
243
329
|
|
|
244
330
|
for level, group in self.description['order'].items():
|
|
245
331
|
for names in group:
|
|
246
332
|
for name in names:
|
|
247
|
-
if name not in self.
|
|
248
|
-
if name not in self.
|
|
333
|
+
if name not in self.description['dependents']:
|
|
334
|
+
if name not in self.dims:
|
|
249
335
|
self.dims[name] = (level, )
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
336
|
+
else:
|
|
337
|
+
d = set()
|
|
338
|
+
for n in self.description['dependents'][name]:
|
|
339
|
+
d.update(self.dims[n])
|
|
340
|
+
if name not in self.dims:
|
|
254
341
|
self.dims[name] = tuple(sorted(d))
|
|
342
|
+
else:
|
|
343
|
+
self.dims[name] = tuple(
|
|
344
|
+
sorted(set(self.dims[name]) | d))
|
|
255
345
|
|
|
256
346
|
if self.is_local_record():
|
|
257
347
|
self.database = Path(self.database)
|
|
@@ -301,9 +391,9 @@ class Record():
|
|
|
301
391
|
self.flush()
|
|
302
392
|
|
|
303
393
|
def __getitem__(self, key):
|
|
304
|
-
return self.get(key)
|
|
394
|
+
return self.get(key, buffer_to_array=True)
|
|
305
395
|
|
|
306
|
-
def get(self, key, default=_notgiven, buffer_to_array=
|
|
396
|
+
def get(self, key, default=_notgiven, buffer_to_array=False, slice=None):
|
|
307
397
|
if self.is_remote_record():
|
|
308
398
|
with ZMQContextManager(zmq.DEALER,
|
|
309
399
|
connect=self.database) as socket:
|
|
@@ -314,19 +404,19 @@ class Record():
|
|
|
314
404
|
})
|
|
315
405
|
ret = socket.recv_pyobj()
|
|
316
406
|
if isinstance(ret, BufferList):
|
|
317
|
-
socket.send_pyobj({
|
|
318
|
-
'method': 'bufferlist_slice',
|
|
319
|
-
'record_id': self.id,
|
|
320
|
-
'key': key,
|
|
321
|
-
'slice': slice
|
|
322
|
-
})
|
|
323
|
-
lst = socket.recv_pyobj()
|
|
324
|
-
ret._list = lst
|
|
325
|
-
ret._slice = slice
|
|
326
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
|
|
327
417
|
return ret.array()
|
|
328
418
|
else:
|
|
329
|
-
ret.
|
|
419
|
+
ret._data_id = self.database, self.id, key
|
|
330
420
|
return ret
|
|
331
421
|
else:
|
|
332
422
|
return ret
|
qulab/scan/scan.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import copy
|
|
2
3
|
import datetime
|
|
3
4
|
import inspect
|
|
4
5
|
import itertools
|
|
@@ -7,6 +8,7 @@ import re
|
|
|
7
8
|
import sys
|
|
8
9
|
import uuid
|
|
9
10
|
import warnings
|
|
11
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
10
12
|
from graphlib import TopologicalSorter
|
|
11
13
|
from pathlib import Path
|
|
12
14
|
from types import MethodType
|
|
@@ -156,6 +158,11 @@ class Promise():
|
|
|
156
158
|
return Promise(self.task, None, attr)
|
|
157
159
|
|
|
158
160
|
|
|
161
|
+
def _run_function_in_process(buf):
|
|
162
|
+
func, args, kwds = dill.loads(buf)
|
|
163
|
+
return func(*args, **kwds)
|
|
164
|
+
|
|
165
|
+
|
|
159
166
|
class Scan():
|
|
160
167
|
|
|
161
168
|
def __new__(cls, *args, mixin=None, **kwds):
|
|
@@ -175,6 +182,8 @@ class Scan():
|
|
|
175
182
|
database: str | Path
|
|
176
183
|
| None = f'tcp://127.0.0.1:{default_record_port}',
|
|
177
184
|
dump_globals: bool = False,
|
|
185
|
+
max_workers: int = 4,
|
|
186
|
+
max_promise: int = 100,
|
|
178
187
|
mixin=None):
|
|
179
188
|
self.id = task_uuid()
|
|
180
189
|
self.record = None
|
|
@@ -206,23 +215,21 @@ class Scan():
|
|
|
206
215
|
self._variables = {}
|
|
207
216
|
self._main_task = None
|
|
208
217
|
self._sock = None
|
|
209
|
-
self._sem = asyncio.Semaphore(
|
|
218
|
+
self._sem = asyncio.Semaphore(max_promise + 1)
|
|
210
219
|
self._bar: dict[int, tqdm] = {}
|
|
211
220
|
self._hide_pattern_re = re.compile('|'.join(self.description['hiden']))
|
|
212
|
-
self.
|
|
213
|
-
self.
|
|
221
|
+
self._msg_queue = asyncio.Queue()
|
|
222
|
+
self._prm_queue = asyncio.Queue()
|
|
214
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)
|
|
215
227
|
|
|
216
228
|
def __del__(self):
|
|
217
229
|
try:
|
|
218
230
|
self._main_task.cancel()
|
|
219
231
|
except:
|
|
220
232
|
pass
|
|
221
|
-
for task in self._task_pool:
|
|
222
|
-
try:
|
|
223
|
-
task.cancel()
|
|
224
|
-
except:
|
|
225
|
-
pass
|
|
226
233
|
|
|
227
234
|
def __getstate__(self) -> dict:
|
|
228
235
|
state = self.__dict__.copy()
|
|
@@ -230,9 +237,10 @@ class Scan():
|
|
|
230
237
|
del state['_sock']
|
|
231
238
|
del state['_main_task']
|
|
232
239
|
del state['_bar']
|
|
233
|
-
del state['
|
|
234
|
-
del state['
|
|
240
|
+
del state['_msg_queue']
|
|
241
|
+
del state['_prm_queue']
|
|
235
242
|
del state['_sem']
|
|
243
|
+
del state['_executors']
|
|
236
244
|
return state
|
|
237
245
|
|
|
238
246
|
def __setstate__(self, state: dict) -> None:
|
|
@@ -241,12 +249,20 @@ class Scan():
|
|
|
241
249
|
self._sock = None
|
|
242
250
|
self._main_task = None
|
|
243
251
|
self._bar = {}
|
|
244
|
-
self.
|
|
245
|
-
self.
|
|
246
|
-
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)
|
|
247
256
|
for opt in self.description['optimizers'].values():
|
|
248
257
|
opt.scanner = self
|
|
249
258
|
|
|
259
|
+
def __del__(self):
|
|
260
|
+
try:
|
|
261
|
+
self._main_task.cancel()
|
|
262
|
+
except:
|
|
263
|
+
pass
|
|
264
|
+
self._executors.shutdown()
|
|
265
|
+
|
|
250
266
|
@property
|
|
251
267
|
def current_level(self):
|
|
252
268
|
return self._current_level
|
|
@@ -255,8 +271,8 @@ class Scan():
|
|
|
255
271
|
def variables(self) -> dict[str, Any]:
|
|
256
272
|
return self._variables
|
|
257
273
|
|
|
258
|
-
async def
|
|
259
|
-
|
|
274
|
+
async def _emit(self, current_level, step, position, variables: dict[str,
|
|
275
|
+
Any]):
|
|
260
276
|
for key, value in list(variables.items()):
|
|
261
277
|
if inspect.isawaitable(value) and not self.hiden(key):
|
|
262
278
|
variables[key] = await value
|
|
@@ -279,6 +295,11 @@ class Scan():
|
|
|
279
295
|
for k, v in variables.items() if not self.hiden(k)
|
|
280
296
|
})
|
|
281
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
|
+
|
|
282
303
|
def hide(self, name: str):
|
|
283
304
|
self.description['hiden'].append(name)
|
|
284
305
|
self._hide_pattern_re = re.compile('|'.join(self.description['hiden']))
|
|
@@ -288,11 +309,11 @@ class Scan():
|
|
|
288
309
|
|
|
289
310
|
async def _filter(self, variables: dict[str, Any], level: int = 0):
|
|
290
311
|
try:
|
|
291
|
-
return all([
|
|
292
|
-
|
|
312
|
+
return all(await asyncio.gather(*[
|
|
313
|
+
call_function(fun, variables) for fun in itertools.chain(
|
|
293
314
|
self.description['filters'].get(level, []),
|
|
294
315
|
self.description['filters'].get(-1, []))
|
|
295
|
-
])
|
|
316
|
+
]))
|
|
296
317
|
except:
|
|
297
318
|
return True
|
|
298
319
|
|
|
@@ -431,11 +452,15 @@ class Scan():
|
|
|
431
452
|
|
|
432
453
|
async def _update_progress(self):
|
|
433
454
|
while True:
|
|
434
|
-
task = await self.
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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()
|
|
439
464
|
|
|
440
465
|
async def run(self):
|
|
441
466
|
assymbly(self.description)
|
|
@@ -451,44 +476,41 @@ class Scan():
|
|
|
451
476
|
await self._run()
|
|
452
477
|
|
|
453
478
|
async def _run(self):
|
|
454
|
-
|
|
455
|
-
self.
|
|
479
|
+
send_msg = asyncio.create_task(self._send_msg())
|
|
480
|
+
update_progress_task = asyncio.create_task(self._update_progress())
|
|
481
|
+
|
|
456
482
|
self._variables = {'self': self}
|
|
457
|
-
|
|
483
|
+
|
|
484
|
+
await update_variables(self._variables, self.description['consts'],
|
|
485
|
+
self.description['setters'])
|
|
458
486
|
for level, total in self.description['total'].items():
|
|
459
487
|
if total == np.inf:
|
|
460
488
|
total = None
|
|
461
489
|
self._bar[level] = tqdm(total=total)
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
self.variables[name])
|
|
470
|
-
if inspect.isawaitable(coro):
|
|
471
|
-
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
|
+
|
|
472
497
|
self.record = await self.create_record()
|
|
473
498
|
await self.work()
|
|
474
499
|
for level, bar in self._bar.items():
|
|
475
500
|
bar.close()
|
|
476
501
|
|
|
477
|
-
while not self._task_queue.empty():
|
|
478
|
-
evt = self._task_queue.get_nowait()
|
|
479
|
-
if isinstance(evt, asyncio.Event):
|
|
480
|
-
evt.set()
|
|
481
|
-
elif inspect.isawaitable(evt):
|
|
482
|
-
await evt
|
|
483
502
|
if self._single_step:
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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()
|
|
492
514
|
return self.variables
|
|
493
515
|
|
|
494
516
|
async def done(self):
|
|
@@ -535,8 +557,8 @@ class Scan():
|
|
|
535
557
|
return
|
|
536
558
|
step = 0
|
|
537
559
|
position = 0
|
|
538
|
-
self.
|
|
539
|
-
self.
|
|
560
|
+
self._prm_queue.put_nowait(self._reset_progress_bar(
|
|
561
|
+
self.current_level))
|
|
540
562
|
async for variables in _iter_level(
|
|
541
563
|
self.variables,
|
|
542
564
|
self.description['loops'].get(self.current_level, []),
|
|
@@ -547,23 +569,18 @@ class Scan():
|
|
|
547
569
|
if await self._filter(variables, self.current_level - 1):
|
|
548
570
|
yield variables
|
|
549
571
|
self._single_step = False
|
|
550
|
-
|
|
551
|
-
self.emit(self.current_level - 1, step, position,
|
|
552
|
-
variables.copy()))
|
|
572
|
+
self.emit(self.current_level - 1, step, position, variables)
|
|
553
573
|
step += 1
|
|
554
574
|
position += 1
|
|
555
575
|
self._current_level -= 1
|
|
556
|
-
self.
|
|
576
|
+
self._prm_queue.put_nowait(
|
|
557
577
|
self._update_progress_bar(self.current_level, 1))
|
|
558
578
|
if self.current_level == 0:
|
|
559
|
-
|
|
579
|
+
self.emit(self.current_level - 1, 0, 0, {})
|
|
560
580
|
for name, value in self.variables.items():
|
|
561
581
|
if inspect.isawaitable(value):
|
|
562
582
|
self.variables[name] = await value
|
|
563
|
-
|
|
564
|
-
task = self._task_queue.get_nowait()
|
|
565
|
-
if inspect.isawaitable(task):
|
|
566
|
-
await task
|
|
583
|
+
await self._prm_queue.join()
|
|
567
584
|
|
|
568
585
|
async def work(self, **kwds):
|
|
569
586
|
if self.current_level in self.description['actions']:
|
|
@@ -588,7 +605,8 @@ class Scan():
|
|
|
588
605
|
"""
|
|
589
606
|
self.description['actions'][level] = action
|
|
590
607
|
|
|
591
|
-
async def promise(self, awaitable: Awaitable
|
|
608
|
+
async def promise(self, awaitable: Awaitable | Callable, *args,
|
|
609
|
+
**kwds) -> Promise:
|
|
592
610
|
"""
|
|
593
611
|
Promise to calculate asynchronous function and return the result in future.
|
|
594
612
|
|
|
@@ -601,8 +619,19 @@ class Scan():
|
|
|
601
619
|
if inspect.isawaitable(awaitable):
|
|
602
620
|
async with self._sem:
|
|
603
621
|
task = asyncio.create_task(self._await(awaitable))
|
|
604
|
-
self.
|
|
622
|
+
self._prm_queue.put_nowait(task)
|
|
605
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)
|
|
606
635
|
else:
|
|
607
636
|
return awaitable
|
|
608
637
|
|
|
@@ -711,18 +740,18 @@ def assymbly(description):
|
|
|
711
740
|
except:
|
|
712
741
|
pass
|
|
713
742
|
|
|
714
|
-
dependents = description['dependents']
|
|
743
|
+
dependents = copy.deepcopy(description['dependents'])
|
|
715
744
|
|
|
716
745
|
for level in levels:
|
|
717
746
|
range_list = description['loops'].get(level, [])
|
|
718
747
|
if level > 0:
|
|
719
748
|
if f'#__loop_{level}' not in description['dependents']:
|
|
720
|
-
dependents[f'#__loop_{level}'] =
|
|
721
|
-
dependents[f'#__loop_{level}'].
|
|
749
|
+
dependents[f'#__loop_{level}'] = set()
|
|
750
|
+
dependents[f'#__loop_{level}'].add(f'#__loop_{level-1}')
|
|
722
751
|
for name, _ in range_list:
|
|
723
752
|
if name not in description['dependents']:
|
|
724
|
-
dependents[name] =
|
|
725
|
-
dependents[name].
|
|
753
|
+
dependents[name] = set()
|
|
754
|
+
dependents[name].add(f'#__loop_{level}')
|
|
726
755
|
|
|
727
756
|
def _get_all_depends(key, graph):
|
|
728
757
|
ret = set()
|
|
@@ -784,13 +813,17 @@ def assymbly(description):
|
|
|
784
813
|
return description
|
|
785
814
|
|
|
786
815
|
|
|
787
|
-
async def
|
|
816
|
+
async def update_variables(variables: dict[str, Any], updates: dict[str, Any],
|
|
817
|
+
setters: dict[str, Callable]):
|
|
818
|
+
coros = []
|
|
788
819
|
for name, value in updates.items():
|
|
789
820
|
if name in setters:
|
|
790
821
|
coro = setters[name](value)
|
|
791
822
|
if inspect.isawaitable(coro):
|
|
792
|
-
|
|
823
|
+
coros.append(coro)
|
|
793
824
|
variables[name] = value
|
|
825
|
+
if coros:
|
|
826
|
+
await asyncio.gather(*coros)
|
|
794
827
|
|
|
795
828
|
|
|
796
829
|
async def _iter_level(variables,
|
|
@@ -823,31 +856,23 @@ async def _iter_level(variables,
|
|
|
823
856
|
maxiter = min(maxiter, opt_cfg.maxiter)
|
|
824
857
|
|
|
825
858
|
async for args in async_zip(*iters_d.values(), range(maxiter)):
|
|
826
|
-
await
|
|
827
|
-
|
|
859
|
+
await update_variables(variables, dict(zip(iters_d.keys(), args[:-1])),
|
|
860
|
+
setters)
|
|
828
861
|
for name, opt in opts.items():
|
|
829
862
|
args = opt.ask()
|
|
830
863
|
opt_cfg = optimizers[name]
|
|
831
|
-
await
|
|
864
|
+
await update_variables(variables, {
|
|
832
865
|
n: v
|
|
833
866
|
for n, v in zip(opt_cfg.dimensions.keys(), args)
|
|
834
867
|
}, setters)
|
|
835
868
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
await _update_variables(variables, {
|
|
840
|
-
name:
|
|
841
|
-
await call_function(functions[name], variables)
|
|
842
|
-
}, setters)
|
|
869
|
+
await update_variables(
|
|
870
|
+
variables, await call_many_functions(order, functions, variables),
|
|
871
|
+
setters)
|
|
843
872
|
|
|
844
873
|
yield variables
|
|
845
874
|
|
|
846
|
-
|
|
847
|
-
for name in group:
|
|
848
|
-
if name in getters:
|
|
849
|
-
variables[name] = await call_function(
|
|
850
|
-
getters[name], variables)
|
|
875
|
+
variables.update(await call_many_functions(order, getters, variables))
|
|
851
876
|
|
|
852
877
|
for name, opt in opts.items():
|
|
853
878
|
opt_cfg = optimizers[name]
|
|
@@ -865,10 +890,28 @@ async def _iter_level(variables,
|
|
|
865
890
|
for name, opt in opts.items():
|
|
866
891
|
opt_cfg = optimizers[name]
|
|
867
892
|
result = opt.get_result()
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
893
|
+
await update_variables(
|
|
894
|
+
variables, {
|
|
895
|
+
name: value
|
|
896
|
+
for name, value in zip(opt_cfg.dimensions.keys(), result.x)
|
|
897
|
+
}, setters)
|
|
872
898
|
variables[name] = result.fun
|
|
873
899
|
if opts:
|
|
874
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
|