QuLab 2.3.5__cp310-cp310-win_amd64.whl → 2.4.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.
@@ -0,0 +1,90 @@
1
+ import loguru
2
+
3
+ from .storage import Result
4
+
5
+
6
+ def _query_config(name: str, default=None):
7
+ import pickle
8
+
9
+ try:
10
+ with open('parameters.pkl', 'rb') as f:
11
+ parameters = pickle.load(f)
12
+ except:
13
+ parameters = {}
14
+
15
+ return parameters.get(name, default)
16
+
17
+
18
+ def _update_config(updates):
19
+ import pickle
20
+
21
+ try:
22
+ with open('parameters.pkl', 'rb') as f:
23
+ parameters = pickle.load(f)
24
+ except:
25
+ parameters = {}
26
+
27
+ for k, v in updates.items():
28
+ parameters[k] = v
29
+
30
+ with open('parameters.pkl', 'wb') as f:
31
+ pickle.dump(parameters, f)
32
+
33
+
34
+ def update_parameters(result: Result):
35
+ update_config(result.params)
36
+
37
+
38
+ def result_to_params(result: Result | None) -> tuple | None:
39
+ if result is None:
40
+ return None
41
+
42
+ state = 'Bad data'
43
+ match (result.in_spec, result.bad_data):
44
+ case (True, False):
45
+ state = 'In spec'
46
+ case (False, True):
47
+ state = 'Bad data'
48
+ case (False, False):
49
+ state = 'Out of spec'
50
+
51
+ return state, result.params, result.info
52
+
53
+
54
+ def params_to_result(params: tuple) -> Result:
55
+ state, cali, info = params
56
+ result = Result()
57
+ if state in ['In spec', 'OK']:
58
+ result.in_spec = True
59
+ result.bad_data = False
60
+ elif state == ['Bad data', 'Bad']:
61
+ result.bad_data = True
62
+ result.in_spec = False
63
+ else:
64
+ result.bad_data = False
65
+ result.in_spec = False
66
+ result.params = cali
67
+ result.info = info
68
+ return result
69
+
70
+
71
+ query_config = _query_config
72
+ update_config = _update_config
73
+
74
+
75
+ def set_config_api(query_method, update_method):
76
+ """
77
+ Set the query and update methods for the config.
78
+
79
+ Args:
80
+ query_method: The query method.
81
+ the method should take a key and return the value.
82
+ update_method: The update method.
83
+ the method should take a dict of updates.
84
+ """
85
+ global query_config, update_config
86
+
87
+ query_config = query_method
88
+ update_config = update_method
89
+
90
+ return query_config, update_config
@@ -0,0 +1,107 @@
1
+ from pathlib import Path
2
+
3
+ from .load import load_workflow
4
+
5
+
6
+ class Node:
7
+
8
+ def __init__(self, name: str):
9
+ self.name = name
10
+ self.dependents = []
11
+
12
+
13
+ class Tree:
14
+
15
+ def __init__(self):
16
+ self.nodes = {}
17
+ self.heads = []
18
+
19
+ def add_node(self, node: str):
20
+ self.nodes[node] = Node(node)
21
+
22
+
23
+ def dependent_tree(node: str, code_path: str | Path) -> dict[str, list[str]]:
24
+ '''
25
+ Returns a dict of nodes and their dependents.
26
+ '''
27
+ tree = {}
28
+ for n in load_workflow(node, code_path).depends()[0]:
29
+ tree[n] = dependent_tree(n, code_path)
30
+ return tree
31
+
32
+
33
+ def workflow_template(deps: list[str]) -> str:
34
+ return f"""
35
+ from loguru import logger
36
+
37
+ import numpy as np
38
+
39
+
40
+ # 多长时间应该检查一次校准实验,单位是秒。
41
+ __timeout__ = 200
42
+
43
+ def depends():
44
+ return [{deps!r}]
45
+
46
+
47
+ def calibrate():
48
+ logger.info(f"run {{__name__}}")
49
+
50
+ # calibrate 是一个完整的校准实验,如power Rabi,Ramsey等。
51
+ # 你需要足够的扫描点,以使得后续的 analyze 可以拟合出合适的参数。
52
+
53
+ # 这里只是一个示例,实际上你需要在这里写上你的校准代码。
54
+ x = np.linspace(0, 2*np.pi, 101)
55
+ y = []
56
+ for i in x:
57
+ y.append(np.sin(i))
58
+
59
+ return x, y
60
+
61
+
62
+ def analyze(*args, history):
63
+ import random
64
+
65
+ # 完整校准后的状态有两种:OK 和 Bad,分别对应校准成功和校准失败。
66
+ # 校准失败是指出现坏数据,无法简单通过重新运行本次校准解决,需要
67
+ # 检查前置步骤。
68
+ state = random.choice(['OK', 'Bad'])
69
+
70
+ # 参数是一个字典,包含了本次校准得到的参数,后续会更新到config表中。
71
+ parameters = {{'gate.R.Q1.params.amp':1}}
72
+
73
+ # 其他信息可以是任何可序列化的内容,你可以将你想要记录的信息放在这里。
74
+ # 下次校准分析时,这些信息也会在 history 参数中一起传入,帮助你在下
75
+ # 次分析时对比参考。
76
+ other_infomation = {{}}
77
+
78
+ return state, parameters, other_infomation
79
+
80
+
81
+ def check():
82
+ logger.info(f"check {{__name__}}")
83
+
84
+ # check 是一个快速检查实验,用于检查校准是否过时。
85
+ # 你只需要少数扫描点,让后续的 check_analyze 知道参数是否漂移,数据
86
+ # 坏没坏就够了,不要求拟合。
87
+
88
+ # 这里只是一个示例,实际上你需要在这里写上你的检查代码。
89
+ x = np.linspace(0, 2*np.pi, 5)
90
+ y = []
91
+ for i in x:
92
+ y.append(np.sin(i))
93
+
94
+ return x, y
95
+
96
+
97
+ def check_analyze(*args, history):
98
+ import random
99
+
100
+ # 状态有三种:Outdated, OK, Bad,分别对应过时、正常、坏数据。
101
+ # Outdated 是指数据过时,即参数漂了,需要重新校准。
102
+ # OK 是指数据正常,参数也没漂,不用重新校准。
103
+ # Bad 是指数据坏了,无法校准,需要检查前置步骤。
104
+ state = random.choice(['Outdated', 'OK', 'Bad'])
105
+
106
+ return state, {{}}, {{}}
107
+ """
Binary file
qulab/scan/curd.py CHANGED
@@ -7,7 +7,7 @@ from typing import Sequence, Type, Union
7
7
  from sqlalchemy.orm import Query, Session, aliased
8
8
  from sqlalchemy.orm.exc import NoResultFound
9
9
  from sqlalchemy.orm.session import Session
10
- from waveforms.dicttree import foldDict
10
+ from ..dicttree import foldDict
11
11
 
12
12
  from .models import (Cell, Comment, Config, InputText, Notebook, Record,
13
13
  Report, Sample, Tag, utcnow)
qulab/scan/expression.py CHANGED
@@ -420,6 +420,10 @@ class Expression():
420
420
  return False
421
421
 
422
422
  def value(self, env=_default_env):
423
+ if isinstance(env, dict):
424
+ e = Env()
425
+ e.variables = env
426
+ env = e
423
427
  if self.changed(env):
424
428
  self.cache = self.eval(env)
425
429
  return self.cache
qulab/scan/models.py CHANGED
@@ -8,7 +8,6 @@ from sqlalchemy import (Column, DateTime, Float, ForeignKey, Integer,
8
8
  from sqlalchemy.orm import (backref, declarative_base, relationship,
9
9
  sessionmaker)
10
10
  from sqlalchemy.orm.session import Session
11
- from waveforms.security import InvalidKey, encryptPassword, verifyPassword
12
11
 
13
12
 
14
13
  def utcnow():
@@ -107,15 +106,15 @@ class User(Base):
107
106
  attachments = relationship('Attachment', back_populates='user')
108
107
  comments = relationship('Comment', back_populates='user')
109
108
 
110
- def setPassword(self, password):
111
- self.hashed_password = encryptPassword(password)
109
+ # def setPassword(self, password):
110
+ # self.hashed_password = encryptPassword(password)
112
111
 
113
- def verify(self, password):
114
- try:
115
- verifyPassword(password, self.hashed_password)
116
- return True
117
- except InvalidKey:
118
- return False
112
+ # def verify(self, password):
113
+ # try:
114
+ # verifyPassword(password, self.hashed_password)
115
+ # return True
116
+ # except InvalidKey:
117
+ # return False
119
118
 
120
119
  def __repr__(self):
121
120
  return f"User(name='{self.name}')"
@@ -526,13 +525,13 @@ def create_tables(engine, tables_only=False):
526
525
  root_role = Role(name='root')
527
526
  admin_role = Role(name='admin')
528
527
  root_user = User(name='root')
529
- root_user.setPassword('123')
528
+ # root_user.setPassword('123')
530
529
  root_user.roles.append(root_role)
531
530
  root_user.roles.append(admin_role)
532
531
 
533
532
  guest_role = Role(name='guest')
534
533
  guest_user = User(name='guest')
535
- guest_user.setPassword('')
534
+ # guest_user.setPassword('')
536
535
  guest_user.roles.append(guest_role)
537
536
 
538
537
  t1 = SampleAccountType(name='factory')
qulab/scan/server.py CHANGED
@@ -73,13 +73,13 @@ def clear_cache():
73
73
  return
74
74
 
75
75
  logger.debug(f"clear_cache record_cache: {len(record_cache)}")
76
- for (k, (t, r),
76
+ for ((k, (t, r)),
77
77
  i) in zip(sorted(record_cache.items(), key=lambda x: x[1][0]),
78
78
  range(len(record_cache) - CACHE_SIZE)):
79
79
  del record_cache[k]
80
80
 
81
81
  logger.debug(f"clear_cache buffer_list_cache: {len(buffer_list_cache)}")
82
- for (k, (t, r),
82
+ for ((k, (t, r)),
83
83
  i) in zip(sorted(buffer_list_cache.items(), key=lambda x: x[1][0]),
84
84
  range(len(buffer_list_cache) - CACHE_SIZE)):
85
85
  del buffer_list_cache[k]
@@ -276,7 +276,10 @@ async def handle(session: Session, request: Request, datapath: Path):
276
276
  case 'notebook_extend':
277
277
  notebook = session.get(Notebook, msg['notebook_id'])
278
278
  inputCells = msg.get('input_cells', [""])
279
- aready_saved = len(notebook.cells)
279
+ try:
280
+ aready_saved = len(notebook.cells)
281
+ except:
282
+ aready_saved = 0
280
283
  if len(inputCells) > aready_saved:
281
284
  for cell in inputCells[aready_saved:]:
282
285
  cell = create_cell(session, notebook, cell)
@@ -12,6 +12,14 @@ Decorator = Callable[[Callable], Callable]
12
12
  _buildin_set = set
13
13
 
14
14
 
15
+ class Source():
16
+ pass
17
+
18
+
19
+ class Sink():
20
+ pass
21
+
22
+
15
23
  def action(key: str,
16
24
  method: Literal['get', 'set', 'post', 'delete'] = 'get',
17
25
  **kwds) -> Decorator:
qulab/sys/device/utils.py CHANGED
@@ -2,6 +2,20 @@ import struct
2
2
 
3
3
  import numpy as np
4
4
 
5
+ types = {
6
+ "b" : ( int, 'b'), "B" : ( int, 'B'),
7
+ "h" : ( int, 'h'), "H" : ( int, 'H'),
8
+ "i" : ( int, 'i'), "I" : ( int, 'I'),
9
+ "q" : ( int, 'q'), "Q" : ( int, 'Q'),
10
+ "f" : (float, 'f'), "d" : (float, 'd'),
11
+ "int8" : ( int, 'b'), "uint8" : ( int, 'B'),
12
+ "int16" : ( int, 'h'), "uint16" : ( int, 'H'),
13
+ "int32" : ( int, 'i'), "uint32" : ( int, 'I'),
14
+ "int64" : ( int, 'q'), "uint64" : ( int, 'Q'),
15
+ "float" : (float, 'f'), "double" : (float, 'd'),
16
+ "float32": (float, 'f'), "float64": (float, 'd')
17
+ } # yapf: disable
18
+
5
19
 
6
20
  def IEEE_488_2_BinBlock(datalist, dtype="int16", is_big_endian=True):
7
21
  """
@@ -16,19 +30,6 @@ def IEEE_488_2_BinBlock(datalist, dtype="int16", is_big_endian=True):
16
30
  binblock, header
17
31
  二进制块, 以及其 'header'
18
32
  """
19
- types = {"b" : ( int, 'b'), "B" : ( int, 'B'),
20
- "h" : ( int, 'h'), "H" : ( int, 'H'),
21
- "i" : ( int, 'i'), "I" : ( int, 'I'),
22
- "q" : ( int, 'q'), "Q" : ( int, 'Q'),
23
- "f" : (float, 'f'), "d" : (float, 'd'),
24
- "int8" : ( int, 'b'), "uint8" : ( int, 'B'),
25
- "int16" : ( int, 'h'), "uint16" : ( int, 'H'),
26
- "int32" : ( int, 'i'), "uint32" : ( int, 'I'),
27
- "int64" : ( int, 'q'), "uint64" : ( int, 'Q'),
28
- "float" : (float, 'f'), "double" : (float, 'd'),
29
- "float32": (float, 'f'), "float64": (float, 'd')
30
- } # yapf: disable
31
-
32
33
  if isinstance(datalist, bytes):
33
34
  datablock = datalist
34
35
  else:
@@ -44,3 +45,35 @@ def IEEE_488_2_BinBlock(datalist, dtype="int16", is_big_endian=True):
44
45
  header = '#%d%s' % (len(size), size)
45
46
 
46
47
  return header.encode() + datablock
48
+
49
+
50
+ def decode_IEEE_488_2_BinBlock(data, dtype="int16", is_big_endian=True):
51
+ """
52
+ 解析 IEEE 488.2 标准二进制块
53
+
54
+ Args:
55
+ data : 二进制块
56
+ dtype : 数据类型
57
+ endian : 字节序
58
+
59
+ Returns:
60
+ datalist
61
+ """
62
+ if isinstance(data, bytes):
63
+ header = data[:2]
64
+ size = int(data[2:2 + int(header[1:2])])
65
+ assert size == len(data) - 2 - int(header[1:2]), "data size error"
66
+ datablock = data[2 + int(header[1:2]):size + 2 + int(header[1:2])]
67
+ else:
68
+ raise ValueError("data must be bytes")
69
+
70
+ if is_big_endian:
71
+ endianc = '>'
72
+ else:
73
+ endianc = '<'
74
+ datalist = list(
75
+ struct.unpack(
76
+ '%s%d%s' % (endianc, size // struct.calcsize(types[dtype][1]),
77
+ types[dtype][1]), datablock))
78
+
79
+ return datalist
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+ import random
3
+
4
+ import zmq
5
+ import zmq.asyncio
6
+
7
+
8
+ async def handle_client(socket, identity, message):
9
+ print(f"Received request from {identity}: {message.decode()}")
10
+ # 随机延时 0 到 3 秒
11
+ await asyncio.sleep(random.uniform(0, 3))
12
+ task_id = random.randint(1000, 9999) # 随机生成一个任务 ID
13
+ await socket.send_multipart([identity, f"Task ID: {task_id}".encode()])
14
+ print(f"Sent Task ID {task_id} to {identity}")
15
+
16
+
17
+ async def server():
18
+ context = zmq.asyncio.Context()
19
+ socket = context.socket(zmq.ROUTER)
20
+ socket.bind("tcp://*:5555")
21
+
22
+ while True:
23
+ try:
24
+ identity, message = await socket.recv_multipart()
25
+ asyncio.create_task(handle_client(socket, identity, message))
26
+ except Exception as e:
27
+ print(f"An error occurred: {e}")
28
+ break
29
+
30
+ socket.close()
31
+ context.term()
32
+
33
+
34
+ if __name__ == "__main__":
35
+ asyncio.run(server())
qulab/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.3.5"
1
+ __version__ = "2.4.0"
@@ -239,8 +239,8 @@ def plot_img(x,
239
239
  kwds.setdefault('aspect', 'auto')
240
240
  kwds.setdefault('interpolation', 'nearest')
241
241
 
242
- vmin = kwds.get('vmin', np.nanmin(z))
243
- vmax = kwds.get('vmax', np.nanmax(z))
242
+ vmin = kwds.pop('vmin', np.nanmin(z))
243
+ vmax = kwds.pop('vmax', np.nanmax(z))
244
244
  if zscale == 'log':
245
245
  kwds.setdefault('norm', LogNorm(vmax=vmax, vmin=vmin))
246
246
  elif zscale == 'symlog':
@@ -262,7 +262,8 @@ def plot_img(x,
262
262
  kwds.pop('origin', None)
263
263
  kwds.pop('aspect', None)
264
264
  kwds.pop('interpolation', None)
265
- pc = ax.pcolormesh(x, y, z, **kwds)
265
+ shading = kwds.pop('shading', 'nearest')
266
+ pc = ax.pcolormesh(x, y, z, shading=shading, **kwds)
266
267
  xlabel = f"{xlabel} [{x_unit}]" if x_unit else xlabel
267
268
  ylabel = f"{ylabel} [{y_unit}]" if y_unit else ylabel
268
269
  ax.set_xlabel(xlabel)