QuLab 2.1.1__cp311-cp311-win_amd64.whl → 2.1.2__cp311-cp311-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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: QuLab
3
- Version: 2.1.1
3
+ Version: 2.1.2
4
4
  Summary: contral instruments and manage data
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -1,7 +1,7 @@
1
- qulab/__init__.py,sha256=8zLGg-DfQhnDl2Ky0n-zXpN-8e-g7iR0AcaI4l4Vvpk,32
1
+ qulab/__init__.py,sha256=vkFybY8YSsQilYdThPRD83-btPAR41sy_WCXiM-6mME,141
2
2
  qulab/__main__.py,sha256=XN2wrhlmEkTIPq_ZeSaO8rWXfYgD2Czkm9DVFVoCw_U,515
3
- qulab/fun.cp311-win_amd64.pyd,sha256=UDt4HGuuUwWs5ppErwUbge8zg6CnVY4_z-AoonzjuFg,31232
4
- qulab/version.py,sha256=k4SipKIh6P-kJf4P7Os3KD55dGIg3hoiS5pK316IoMg,21
3
+ qulab/fun.cp311-win_amd64.pyd,sha256=pDbiPNpPRjooF6cAGawfNqWkl4mbMhiar3MdLOTP0q4,31232
4
+ qulab/version.py,sha256=FM98Inv2t7vU9Dvod2ccoaPCOtP2LV-rqmhbddOPf9U,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
@@ -12,15 +12,15 @@ qulab/monitor/monitor.py,sha256=2AP-hhg1T6-38mieDm5_ONTIXnXYlIrSyOiAOxDKy0I,2398
12
12
  qulab/monitor/ploter.py,sha256=dg7W28XTwEbBxHVtdPkFV135OQgoQwTi-NJCZQF-HYU,3724
13
13
  qulab/monitor/qt_compat.py,sha256=Eq7zlA4_XstB92NhtAqebtWU_Btw4lcwFO30YxZ-TPE,804
14
14
  qulab/monitor/toolbar.py,sha256=HxqG6ywKFyQJM2Q1s7SnhuzjbyeROczAZKwxztD1WJ8,8213
15
- qulab/scan/__init__.py,sha256=QQtFFMWX9XUcZrq2KGiNgyckoQRGS4p8MhsMWNjidBE,120
15
+ qulab/scan/__init__.py,sha256=RR_0NQcr8Mi3vpWdypydbijQ1rXA0D3DEidQ7xjNslM,133
16
16
  qulab/scan/curd.py,sha256=bEXtcmiaoAv5APToXx5O5tvmqAhE2_LkvdwLsI_8D5M,4662
17
17
  qulab/scan/expression.py,sha256=vwUM9E0OFQal4bljlUtLR3NJu4zGRyuWYrdyZSs3QTU,16199
18
18
  qulab/scan/models.py,sha256=TkiVHF_fUZzYHs4MsCTRh391thpf4Ozd3R_LAU0Gxkg,17657
19
19
  qulab/scan/optimize.py,sha256=MlT4y422CnP961IR384UKryyZh8riNvrPSd2z_MXLEg,2356
20
- qulab/scan/query.py,sha256=ieXz8_YGUuZfQTruJdtKLZT7ZIiYzcJNvnRseitbQDA,11943
21
- qulab/scan/record.py,sha256=jJ_K3QrdEqtHRpG5EtkMRIKcFRNREgMxtoi7a9nMeeI,15535
22
- qulab/scan/recorder.py,sha256=3CrFEs-tyiR3aSxhqFDIdhibHTLzVyxsDXRpovQ8dyI,8804
23
- qulab/scan/scan.py,sha256=bFb20OXam6xj71tvZOws8VZ-iDRqLDHXTrZ8oGA2uDY,30022
20
+ qulab/scan/query.py,sha256=vT1OevzKImqG40plmiPbyvzHVTBzAETo_OxpJHa0UmU,11821
21
+ qulab/scan/record.py,sha256=s1bY4F_2FxIeN9ER-FILslCqc7i0JRAFv9pk0InQmcg,17477
22
+ qulab/scan/recorder.py,sha256=qlUlxksL-beolTU3EupBlKDBGViicrq3ZoxjH6ZVHrY,8964
23
+ qulab/scan/scan.py,sha256=AJ2GxdgTRL165UkNT27qZwJp_ag5j_hevNAY1-fUh7U,30607
24
24
  qulab/scan/server.py,sha256=Q7lX9ms37WbnzuLhrv3YbNrusTsxQUNT9slFqon5VL0,2872
25
25
  qulab/scan/space.py,sha256=OPceWIIrb2KDDQaSxD3Vkzkf9NDSuqWuQoDnKiWqtAo,5381
26
26
  qulab/scan/utils.py,sha256=30qnYvyFyctwcWxOCUpCNxXgGysA7xdIDzYbjwxGUzA,3744
@@ -79,9 +79,9 @@ qulab/visualization/plot_layout.py,sha256=yAnMONOms7_szCdng-8wPpUMPis5UnbaNNzV4K
79
79
  qulab/visualization/plot_seq.py,sha256=h9D0Yl_yO64IwlvBgzMu9EBKr9gg6y8QE55gu2PfTns,2783
80
80
  qulab/visualization/qdat.py,sha256=HubXFu4nfcA7iUzghJGle1C86G6221hicLR0b-GqhKQ,5887
81
81
  qulab/visualization/widgets.py,sha256=HcYwdhDtLreJiYaZuN3LfofjJmZcLwjMfP5aasebgDo,3266
82
- QuLab-2.1.1.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
83
- QuLab-2.1.1.dist-info/METADATA,sha256=nxgn3sJ3bOPGYgZ_3nNqUswtTIJcEzdsaJEGMX0fvi4,3609
84
- QuLab-2.1.1.dist-info/WHEEL,sha256=nSybvzWlmdJnHiUQSY-d7V1ycwEVUTqXiTvr2eshg44,102
85
- QuLab-2.1.1.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
86
- QuLab-2.1.1.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
87
- QuLab-2.1.1.dist-info/RECORD,,
82
+ QuLab-2.1.2.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
83
+ QuLab-2.1.2.dist-info/METADATA,sha256=BawKmH85rDyYCZUqZ1sEDQKzkUnpZX4D-Iy8iiY7AhQ,3609
84
+ QuLab-2.1.2.dist-info/WHEEL,sha256=nSybvzWlmdJnHiUQSY-d7V1ycwEVUTqXiTvr2eshg44,102
85
+ QuLab-2.1.2.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
86
+ QuLab-2.1.2.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
87
+ QuLab-2.1.2.dist-info/RECORD,,
qulab/__init__.py CHANGED
@@ -1 +1,3 @@
1
- from .version import __version__
1
+ from .scan import Scan, get_record, load_record, lookup, lookup_list
2
+ from .version import __version__
3
+ from .visualization import autoplot
Binary file
qulab/scan/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from .expression import Expression, Symbol
2
- from .query import get_record, lookup, lookup_list
2
+ from .query import get_record, load_record, lookup, lookup_list
3
3
  from .scan import Scan
qulab/scan/query.py CHANGED
@@ -6,10 +6,13 @@ import dill
6
6
  import ipywidgets as widgets
7
7
  import zmq
8
8
  from IPython.display import display
9
+ from sqlalchemy import create_engine
10
+ from sqlalchemy.orm import sessionmaker
9
11
 
10
12
  from qulab.sys.rpc.zmq_socket import ZMQContextManager
11
13
 
12
14
  from .record import Record
15
+ from .recorder import get_local_record
13
16
  from .scan import default_server
14
17
 
15
18
 
@@ -26,18 +29,15 @@ def get_record(id, database=default_server) -> Record:
26
29
  d._file = None
27
30
  return d
28
31
  else:
29
- from .models import Record as RecordInDB
30
- from .models import create_engine, sessionmaker
31
-
32
32
  db_file = Path(database) / 'data.db'
33
33
  engine = create_engine(f'sqlite:///{db_file}')
34
34
  Session = sessionmaker(bind=engine)
35
35
  with Session() as session:
36
- path = Path(database) / 'objects' / session.get(RecordInDB,
37
- id).file
38
- with open(path, 'rb') as f:
39
- record = dill.load(f)
40
- return record
36
+ return get_local_record(session, id, database)
37
+
38
+
39
+ def load_record(file):
40
+ return Record.load(file)
41
41
 
42
42
 
43
43
  def _format_tag(tag):
qulab/scan/record.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import itertools
2
2
  import sys
3
3
  import uuid
4
+ import zipfile
4
5
  from pathlib import Path
5
6
  from threading import Lock
6
7
  from types import EllipsisType
@@ -13,7 +14,7 @@ from qulab.sys.rpc.zmq_socket import ZMQContextManager
13
14
 
14
15
  from .space import OptimizeSpace, Space
15
16
 
16
- _notgiven = object()
17
+ _not_given = object()
17
18
 
18
19
 
19
20
  def random_path(base):
@@ -120,6 +121,18 @@ class BufferList():
120
121
  yield pos, value
121
122
  except EOFError:
122
123
  break
124
+ elif isinstance(
125
+ self.file, tuple) and len(self.file) == 2 and isinstance(
126
+ self.file[0], str) and self.file[0].endswith('.zip'):
127
+ f, name = self.file
128
+ with zipfile.ZipFile(f, 'r') as z:
129
+ with z.open(name, 'r') as f:
130
+ while True:
131
+ try:
132
+ pos, value = dill.load(f)
133
+ yield pos, value
134
+ except EOFError:
135
+ break
123
136
 
124
137
  def iter(self):
125
138
  if self._data_id is None:
@@ -327,7 +340,7 @@ class Record():
327
340
  ret = ret.toarray()
328
341
  return ret
329
342
 
330
- def get(self, key, default=_notgiven, buffer_to_array=False, slice=None):
343
+ def get(self, key, default=_not_given, buffer_to_array=False, slice=None):
331
344
  if self.is_remote_record():
332
345
  with ZMQContextManager(zmq.DEALER,
333
346
  connect=self.database) as socket:
@@ -355,7 +368,7 @@ class Record():
355
368
  else:
356
369
  return ret
357
370
  else:
358
- if default is _notgiven:
371
+ if default is _not_given:
359
372
  d = self._items.get(key)
360
373
  else:
361
374
  d = self._items.get(key, default)
@@ -437,6 +450,40 @@ class Record():
437
450
  with open(self._file, 'wb') as f:
438
451
  dill.dump(self, f)
439
452
 
453
+ def export(self, file):
454
+ with zipfile.ZipFile(file,
455
+ 'w',
456
+ compression=zipfile.ZIP_DEFLATED,
457
+ compresslevel=9) as z:
458
+ items = {}
459
+ for key in self.keys():
460
+ value = self.get(key)
461
+ if isinstance(value, BufferList):
462
+ v = BufferList()
463
+ v.lu = value.lu
464
+ v.rd = value.rd
465
+ v.inner_shape = value.inner_shape
466
+ items[key] = v
467
+ with z.open(f'{key}.buf', 'w') as f:
468
+ for pos, data in value.iter():
469
+ dill.dump((pos, data), f)
470
+ else:
471
+ items[key] = value
472
+ with z.open('record.pkl', 'w') as f:
473
+ dill.dump((self.description, items), f)
474
+
475
+ @classmethod
476
+ def load(cls, file: str):
477
+ with zipfile.ZipFile(file, 'r') as z:
478
+ with z.open('record.pkl', 'r') as f:
479
+ description, items = dill.load(f)
480
+ record = cls(None, None, description)
481
+ for key, value in items.items():
482
+ if isinstance(value, BufferList):
483
+ value.file = file, f'{key}.buf'
484
+ record._items[key] = value
485
+ return record
486
+
440
487
  def __repr__(self):
441
488
  return f"<Record: id={self.id} app={self.description['app']}, keys={self.keys()}>"
442
489
 
qulab/scan/recorder.py CHANGED
@@ -28,6 +28,7 @@ else:
28
28
  datapath.mkdir(parents=True, exist_ok=True)
29
29
 
30
30
  record_cache = {}
31
+ CACHE_SIZE = 1024
31
32
 
32
33
 
33
34
  class Request():
@@ -45,11 +46,11 @@ async def reply(req, resp):
45
46
 
46
47
 
47
48
  def clear_cache():
48
- if len(record_cache) < 1024:
49
+ if len(record_cache) < CACHE_SIZE:
49
50
  return
50
51
 
51
52
  for k, (t, _) in zip(sorted(record_cache.items(), key=lambda x: x[1][0]),
52
- range(len(record_cache) - 1024)):
53
+ range(len(record_cache) - CACHE_SIZE)):
53
54
  del record_cache[k]
54
55
 
55
56
 
@@ -58,15 +59,20 @@ def flush_cache():
58
59
  r.flush()
59
60
 
60
61
 
62
+ def get_local_record(session: Session, id: int, datapath: Path) -> Record:
63
+ record_in_db = session.get(RecordInDB, id)
64
+ record_in_db.atime = utcnow()
65
+ path = datapath / 'objects' / record_in_db.file
66
+ with open(path, 'rb') as f:
67
+ record = dill.load(f)
68
+ record.database = datapath
69
+ record._file = path
70
+ return record
71
+
72
+
61
73
  def get_record(session: Session, id: int, datapath: Path) -> Record:
62
74
  if id not in record_cache:
63
- record_in_db = session.get(RecordInDB, id)
64
- record_in_db.atime = utcnow()
65
- path = datapath / 'objects' / record_in_db.file
66
- with open(path, 'rb') as f:
67
- record = dill.load(f)
68
- record.database = datapath
69
- record._file = path
75
+ record = get_local_record(session, id, datapath)
70
76
  else:
71
77
  record = record_cache[id][1]
72
78
  clear_cache()
qulab/scan/scan.py CHANGED
@@ -46,6 +46,10 @@ if os.getenv('QULAB_SERVER'):
46
46
  default_server = os.getenv('QULAB_SERVER')
47
47
  else:
48
48
  default_server = f'tcp://127.0.0.1:{default_record_port}'
49
+ if os.getenv('QULAB_EXECUTOR'):
50
+ default_executor = os.getenv('QULAB_EXECUTOR')
51
+ else:
52
+ default_executor = default_server
49
53
 
50
54
 
51
55
  def task_uuid():
@@ -136,6 +140,7 @@ class Scan():
136
140
  'app': app,
137
141
  'tags': tags,
138
142
  'loops': {},
143
+ 'intrinsic_loops': {},
139
144
  'consts': {},
140
145
  'functions': {},
141
146
  'getters': {},
@@ -287,10 +292,10 @@ class Scan():
287
292
  else:
288
293
  return Symbol(name)
289
294
 
290
- def _add_loop_var(self, name: str, level: int, range):
295
+ def _add_search_space(self, name: str, level: int, space):
291
296
  if level not in self.description['loops']:
292
297
  self.description['loops'][level] = []
293
- self.description['loops'][level].append((name, range))
298
+ self.description['loops'][level].append((name, space))
294
299
 
295
300
  def add_depends(self, name: str, depends: list[str]):
296
301
  if isinstance(depends, str):
@@ -299,7 +304,7 @@ class Scan():
299
304
  self.description['dependents'][name] = set()
300
305
  self.description['dependents'][name].update(depends)
301
306
 
302
- def add_filter(self, func: Callable, level: int):
307
+ def add_filter(self, func: Callable, level: int = -1):
303
308
  """
304
309
  Add a filter function to the scan.
305
310
 
@@ -345,26 +350,33 @@ class Scan():
345
350
 
346
351
  def search(self,
347
352
  name: str,
348
- range: Iterable | Expression | Callable | OptimizeSpace,
353
+ space: Iterable | Expression | Callable | OptimizeSpace,
349
354
  level: int | None = None,
350
- setter: Callable | None = None):
355
+ setter: Callable | None = None,
356
+ intrinsic: bool = False):
351
357
  if level is not None:
352
- assert level >= 0, 'level must be greater than or equal to 0.'
353
- if isinstance(range, OptimizeSpace):
354
- range.name = name
355
- range.optimizer.dimensions[name] = range.space
356
- self._add_loop_var(name, range.optimizer.level, range)
357
- self.add_depends(range.optimizer.name, [name])
358
+ if not intrinsic:
359
+ assert level >= 0, 'level must be greater than or equal to 0.'
360
+ if intrinsic:
361
+ assert isinstance(space, (np.ndarray, list, tuple, range, Space)), \
362
+ 'space must be an instance of np.ndarray, list, tuple, range or Space.'
363
+ self.description['intrinsic_loops'][name] = level
364
+ self.set(name, space)
365
+ elif isinstance(space, OptimizeSpace):
366
+ space.name = name
367
+ space.optimizer.dimensions[name] = space.space
368
+ self._add_search_space(name, space.optimizer.level, space)
369
+ self.add_depends(space.optimizer.name, [name])
358
370
  else:
359
371
  if level is None:
360
372
  raise ValueError('level must be provided.')
361
373
  try:
362
- range = Space.fromarray(range)
374
+ space = Space.fromarray(space)
363
375
  except:
364
376
  pass
365
- self._add_loop_var(name, level, range)
366
- if isinstance(range, Expression) or callable(range):
367
- self.add_depends(name, range.symbols())
377
+ self._add_search_space(name, level, space)
378
+ if isinstance(space, Expression) or callable(space):
379
+ self.add_depends(name, space.symbols())
368
380
  if setter:
369
381
  self.description['setters'][name] = setter
370
382
 
@@ -500,7 +512,7 @@ class Scan():
500
512
  import asyncio
501
513
  self._main_task = asyncio.create_task(self.run())
502
514
 
503
- async def submit(self, server='tcp://127.0.0.1:6788'):
515
+ async def submit(self, server=default_executor):
504
516
  assymbly(self.description)
505
517
  async with ZMQContextManager(zmq.DEALER, connect=server) as socket:
506
518
  await socket.send_pyobj({
@@ -740,7 +752,7 @@ def assymbly(description):
740
752
  keys -= set(ready)
741
753
 
742
754
  axis = {}
743
- independent_variables = set()
755
+ independent_variables = set(description['intrinsic_loops'].keys())
744
756
 
745
757
  for name in description['consts']:
746
758
  axis[name] = ()
qulab/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.1.1"
1
+ __version__ = "2.1.2"
File without changes
File without changes