QuLab 2.11.8__py3-none-any.whl → 2.11.9__py3-none-any.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/executor/analyze.py CHANGED
@@ -4,6 +4,7 @@ import time
4
4
 
5
5
  import pyperclip
6
6
  import zmq
7
+ from rich import print
7
8
 
8
9
  from .storage import Report
9
10
 
qulab/executor/cli.py CHANGED
@@ -25,7 +25,12 @@ from .utils import workflow_template
25
25
 
26
26
  @logger.catch(reraise=True)
27
27
  def run_script(script_path, extra_paths=None):
28
- """Run a script in a new process, inheriting current PYTHONPATH plus any extra paths."""
28
+ """Run a script in a new process, inheriting current PYTHONPATH plus any extra paths.
29
+
30
+ Args:
31
+ script_path (str): Path to the script to be executed
32
+ extra_paths (list, optional): Additional paths to be added to PYTHONPATH
33
+ """
29
34
  import subprocess
30
35
  import sys
31
36
 
@@ -103,8 +108,17 @@ def command_option(command_name):
103
108
  help='The path of the code.')
104
109
  @log_options('create')
105
110
  def create(workflow, code):
106
- """
107
- Create a new workflow file.
111
+ """Create a new workflow file.
112
+
113
+ This command creates a new workflow file with a template structure. The template includes
114
+ basic workflow setup and any unreferenced workflows as potential dependencies.
115
+
116
+ Args:
117
+ workflow: Name of the workflow to create
118
+ code: Directory path where the workflow file will be created. Defaults to current directory.
119
+
120
+ Example:
121
+ $ qulab create my_workflow --code ./workflows
108
122
  """
109
123
  logger.info(f'[CMD]: create {workflow} --code {code}')
110
124
  if code is None:
@@ -133,8 +147,19 @@ def create(workflow, code):
133
147
  help='The modlule name of the api.')
134
148
  @log_options('set')
135
149
  def set(key, value, api):
136
- """
137
- Set a config.
150
+ """Set a configuration value in the registry.
151
+
152
+ This command allows you to set key-value pairs in the configuration registry.
153
+ The value can be any valid Python expression that can be evaluated.
154
+
155
+ Args:
156
+ key: The configuration key to set
157
+ value: The value to set (can be a Python expression)
158
+ api: Optional API module for custom config handling
159
+
160
+ Example:
161
+ $ qulab set Q1.channel.Z NS_DDS.CH1
162
+ $ qulab set gate.R.Q3.params.frequency 5.0e9
138
163
  """
139
164
  logger.info(f'[CMD]: reg set {key} {value} --api {api}')
140
165
  reg = Registry()
@@ -157,8 +182,17 @@ def set(key, value, api):
157
182
  help='The modlule name of the api.')
158
183
  @log_options('get')
159
184
  def get(key, api):
160
- """
161
- Get a config.
185
+ """Get a configuration value from the registry.
186
+
187
+ Retrieves and displays the value associated with a given key from the configuration registry.
188
+
189
+ Args:
190
+ key: The configuration key to retrieve
191
+ api: Optional API module for custom config handling
192
+
193
+ Example:
194
+ $ qulab get Q1.channel
195
+ $ qulab get gate.R.Q3.params.frequency
162
196
  """
163
197
  logger.info(f'[CMD]: reg get {key} --api {api}')
164
198
  reg = Registry()
@@ -177,8 +211,16 @@ def get(key, api):
177
211
  help='The modlule name of the api.')
178
212
  @log_options('delete')
179
213
  def delete(key, api):
180
- """
181
- Delete a config key.
214
+ """Delete a configuration key from the registry.
215
+
216
+ Removes a key and its associated value from the configuration registry.
217
+
218
+ Args:
219
+ key: The configuration key to delete
220
+ api: Optional API module for custom config handling
221
+
222
+ Example:
223
+ $ qulab delete gate.R.Q3.params.block_freq
182
224
  """
183
225
  logger.info(f'[CMD]: reg delete {key} --api {api}')
184
226
  reg = Registry()
@@ -201,8 +243,24 @@ def delete(key, api):
201
243
  help='The format of the config.')
202
244
  @log_options('export')
203
245
  def export(file, api, format):
204
- """
205
- Export a config.
246
+ """Export the configuration registry to a file.
247
+
248
+ Exports all configuration settings to a file in the specified format.
249
+
250
+ Args:
251
+ file: Path to the output file
252
+ api: Optional API module for custom config handling
253
+ format: Output format (pickle, json, or yaml)
254
+
255
+ Supported formats:
256
+ - pickle: Binary format (default)
257
+ - json: JSON text format
258
+ - yaml: YAML text format
259
+
260
+ Example:
261
+ $ qulab export config.pkl
262
+ $ qulab export config.json --format json
263
+ $ qulab export config.yaml --format yaml
206
264
  """
207
265
  logger.info(f'[CMD]: reg export {file} --api {api}')
208
266
  reg = Registry()
@@ -239,8 +297,27 @@ def export(file, api, format):
239
297
  help='The format of the config.')
240
298
  @log_options('load')
241
299
  def load(file, api, format):
242
- """
243
- Load a config.
300
+ """Load configuration settings from a file.
301
+
302
+ Imports configuration settings from a file in the specified format.
303
+ Existing configuration will be cleared before loading the new settings.
304
+
305
+ Args:
306
+ file: Path to the input file or report index number
307
+ api: Optional API module for custom config handling
308
+ format: Input format (pickle, json, yaml, or report)
309
+
310
+ Supported formats:
311
+ - pickle: Binary format (default)
312
+ - json: JSON text format
313
+ - yaml: YAML text format
314
+ - report: Load from a saved report by index
315
+
316
+ Example:
317
+ $ qulab load config.pkl
318
+ $ qulab load config.json --format json
319
+ $ qulab load config.yaml --format yaml
320
+ $ qulab load 123 --format report # Load from report #123
244
321
  """
245
322
  logger.info(f'[CMD]: reg load {file} --api {api}')
246
323
  reg = Registry()
@@ -278,8 +355,16 @@ def load(file, api, format):
278
355
  default=lambda: get_config_value("bootstrap", Path),
279
356
  help='The path of the bootstrap.')
280
357
  def boot(bootstrap):
281
- """
282
- Run a bootstrap script.
358
+ """Run a bootstrap script.
359
+
360
+ Executes a bootstrap script to set up the environment or perform initialization tasks.
361
+ The bootstrap script runs in a new process with the current Python environment.
362
+
363
+ Args:
364
+ bootstrap: Path to the bootstrap script
365
+
366
+ Example:
367
+ $ qulab boot --bootstrap setup.py
283
368
  """
284
369
  if bootstrap is not None:
285
370
  run_script(bootstrap)
@@ -291,7 +376,16 @@ def parse_dynamic_option_value(value):
291
376
  parsed_value = ast.literal_eval(value)
292
377
  except (ValueError, SyntaxError):
293
378
  # 如果解析失败,返回原始字符串
294
- parsed_value = value
379
+ if ',' in value:
380
+ parsed_value = []
381
+ for item in value.split(','):
382
+ try:
383
+ parsed_value.append(ast.literal_eval(item))
384
+ except (ValueError, SyntaxError):
385
+ parsed_value.append(item)
386
+ parsed_value = tuple(parsed_value)
387
+ else:
388
+ parsed_value = value
295
389
  return parsed_value
296
390
 
297
391
 
@@ -311,17 +405,31 @@ def parse_dynamic_options(args):
311
405
  return result
312
406
 
313
407
 
314
- help_doc = """
315
- Run a workflow.
408
+ help_doc = """Run a workflow with specified parameters and options.
409
+
410
+ This command executes a workflow and its dependencies based on the provided configuration.
411
+
412
+ Arguments:
413
+ workflow: The name or path of the workflow to run
414
+
415
+ Options:
416
+ --code, -c: The path containing the workflow code (default: current directory)
417
+ --data, -d: The path for storing logs and data (default: ./logs)
418
+ --api, -a: The module name of the API for configuration handling
419
+ --plot, -p: Generate plots after workflow execution
420
+ --no-dependents, -n: Run only the specified workflow without dependencies
421
+ --retry, -r: Number of retry attempts for failed calibrations (default: 1)
422
+ --freeze: Freeze the configuration table during execution
423
+ --fail-fast, -f: Stop execution on first error
424
+ --veryfy-source-code: Verify source code before execution
316
425
 
317
- If the workflow has entries, run all entries.
318
- If `--no-dependents` is set, only run the workflow itself.
319
- If `--retry` is set, retry the workflow when calibration failed.
320
- If `--freeze` is set, freeze the config table.
321
- If `--plot` is set, plot the report.
322
- If `--api` is set, use the api to get and update the config table.
323
- If `--code` is not set, use the current working directory.
324
- If `--data` is not set, use the `logs` directory in the code path.
426
+ Additional parameters can be passed as key=value pairs and will be available to the workflow.
427
+
428
+ Examples:
429
+ $ qulab run my_workflow
430
+ $ qulab run my_workflow --plot --retry 3
431
+ $ qulab run my_workflow param1=value1 param2=value2
432
+ $ qulab run my_workflow --no-dependents --freeze
325
433
  """
326
434
 
327
435
 
@@ -478,15 +586,30 @@ async def maintain(workflow,
478
586
  plot,
479
587
  fail_fast,
480
588
  veryfy_source_code=True):
481
- """
482
- Maintain a workflow.
483
-
484
- If the workflow has entries, run all entries.
485
- If `--retry` is set, retry the workflow when calibration failed.
486
- If `--plot` is set, plot the report.
487
- If `--api` is set, use the api to get and update the config table.
488
- If `--code` is not set, use the current working directory.
489
- If `--data` is not set, use the `logs` directory in the code path.
589
+ """Maintain a workflow and its dependencies.
590
+
591
+ This command checks and maintains the workflow and its dependencies without executing them.
592
+ It verifies configurations, dependencies, and can generate plots from existing data.
593
+
594
+ Args:
595
+ workflow: Name or path of the workflow to maintain
596
+ code: Directory containing the workflow code
597
+ data: Directory for logs and data
598
+ api: Module name for configuration API
599
+ retry: Number of retry attempts for failed calibrations
600
+ plot: Generate plots from existing data
601
+ fail_fast: Stop on first error
602
+ veryfy_source_code: Verify source code integrity
603
+
604
+ The maintenance process includes:
605
+ 1. Verifying workflow dependencies
606
+ 2. Checking configuration consistency
607
+ 3. Validating source code (if enabled)
608
+ 4. Generating plots (if enabled)
609
+
610
+ Example:
611
+ $ qulab maintain my_workflow --retry 3 --plot
612
+ $ qulab maintain my_workflow --fail-fast
490
613
  """
491
614
  logger.info(
492
615
  f'[CMD]: maintain {workflow} --code {code} --data {data} --api {api}'
@@ -556,13 +679,28 @@ async def maintain(workflow,
556
679
  @command_option('reproduce')
557
680
  @async_command
558
681
  async def reproduce(report_id, code, data, api, plot):
559
- """
560
- Reproduce a report.
561
-
562
- If `--plot` is set, plot the report.
563
- If `--api` is set, use the api to get and update the config table.
564
- If `--code` is not set, use the current working directory.
565
- If `--data` is not set, use the `logs` directory in the code path.
682
+ """Reproduce a workflow execution from a saved report.
683
+
684
+ This command loads a previous execution report and attempts to reproduce the workflow
685
+ with the exact same configuration and conditions.
686
+
687
+ Args:
688
+ report_id: The ID number of the report to reproduce
689
+ code: Directory containing the workflow code
690
+ data: Directory for logs and data
691
+ api: Module name for configuration API
692
+ plot: Generate plots after reproduction
693
+
694
+ The reproduction process:
695
+ 1. Loads the original report by ID
696
+ 2. Restores the exact configuration state
697
+ 3. Executes the workflow with frozen configuration
698
+ 4. Optionally generates plots
699
+ 5. Restores the previous configuration state
700
+
701
+ Example:
702
+ $ qulab reproduce 123 --plot
703
+ $ qulab reproduce 456 --code ./workflows --data ./results
566
704
  """
567
705
  logger.info(
568
706
  f'[CMD]: reproduce {report_id} --code {code} --data {data} --api {api}'
qulab/executor/utils.py CHANGED
@@ -38,6 +38,7 @@ import numpy as np
38
38
  from loguru import logger
39
39
 
40
40
  from qulab import VAR
41
+ from qulab import manual_analysis
41
42
  from qulab.typing import Report
42
43
 
43
44
 
@@ -73,7 +74,8 @@ async def analyze(report: Report, history: Report | None = None) -> Report:
73
74
  history: Report | None
74
75
  上次校准实验数据和分析结果,如果有的话。
75
76
  \"\"\"
76
- import random
77
+ # 如果需要手动分析,请取消注释下面这行
78
+ # return manual_analysis(report, history)
77
79
 
78
80
  # 这里添加你的分析过程,运行 calibrate 得到的数据,在 report.data 里
79
81
  # 你可以得到校准的结果,然后根据这个结果进行分析。
@@ -82,6 +84,7 @@ async def analyze(report: Report, history: Report | None = None) -> Report:
82
84
  # 完整校准后的状态有两种:OK 和 Bad,分别对应校准成功和校准失败。
83
85
  # 校准失败是指出现坏数据,无法简单通过重新运行本次校准解决,需要
84
86
  # 检查前置步骤。
87
+ import random
85
88
  report.state = random.choice(['OK', 'Bad'])
86
89
 
87
90
  # 参数是一个字典,包含了本次校准得到的参数,后续会更新到config表中。
@@ -144,7 +147,7 @@ async def oracle(report: Report,
144
147
 
145
148
  当校准失败时,根据 analyze 的结果,尝试改变某些配置再重新校准整个系统。
146
149
  比如通常我们在死活测不到 rabi 或能谱时,会换一个 idle bias 再试试。这
147
- 里我们凭直觉设的那个 bias 值,就是一个谕示,可以通过 oracle 来设定。
150
+ 里我们凭直觉设的那个 bias 值,就称作一个谕示,可以通过 oracle 来设定。
148
151
 
149
152
  该函数代入的参数 report 是 analyze 函数的返回值。
150
153
  \"\"\"
@@ -161,6 +164,17 @@ async def debug_analyze(
161
164
  code_path: str | Path = get_config_value('code', Path),
162
165
  data_path: str | Path = get_config_value('data', Path),
163
166
  ) -> None:
167
+ """
168
+ 调试 workflow 的分析过程。
169
+
170
+ 该函数会从 data_path 中读取报告,并重新加载对应的 workflow 代码,然后
171
+ 运行 analyze 函数,如果有 plot 函数,还会运行 plot 函数。最后返回包含
172
+ 分析结果的 report 对象。
173
+
174
+ 当你完成一个 workflow 的 calibrate 开发后,可以现运行该 workflow 采
175
+ 集一组数据,然后通过反复修改 analyze 函数,运行该函数,并查看分析结果,
176
+ 来调试 analyze 函数,以期达到满意的效果。
177
+ """
164
178
  from .storage import get_report_by_index
165
179
 
166
180
  report = get_report_by_index(report_index, data_path)
qulab/monitor/__init__.py CHANGED
@@ -1 +1 @@
1
- from .monitor import Monitor, get_monitor
1
+ from .monitor import MonitorUI, get_monitor
qulab/monitor/__main__.py CHANGED
@@ -1,8 +1,36 @@
1
+ """
2
+ QuLab Monitor Command Line Interface
3
+
4
+ This module provides a command-line interface for launching the QuLab monitor.
5
+ It allows users to start a standalone monitor server with configurable settings.
6
+ """
7
+
1
8
  import click
2
9
 
3
- from .monitor import Monitor
10
+ from .monitor import MonitorServer
4
11
 
5
12
 
6
13
  @click.command(name='monitor')
7
- def main():
8
- pass
14
+ @click.option('--columns', '-c', default=4, help='Number of columns in the plot grid')
15
+ @click.option('--height', '-h', default=400, help='Minimum height of each plot in pixels')
16
+ @click.option('--address', '-a', default='127.0.0.1', help='Address to bind the server')
17
+ @click.option('--port', '-p', default=5555, help='Port to bind the server')
18
+ def main(columns: int, height: int, address: str, port: int):
19
+ """Launch a QuLab monitor server.
20
+
21
+ Args:
22
+ columns: Number of columns in the plot grid
23
+ height: Minimum height of each plot in pixels
24
+ address: Address to bind the server (default: 127.0.0.1)
25
+ port: Port to bind the server (default: 5555)
26
+ """
27
+ server = MonitorServer(address=address,
28
+ port=port,
29
+ number_of_columns=columns,
30
+ minimum_height=height)
31
+ try:
32
+ while True:
33
+ import time
34
+ time.sleep(1) # Keep the script running while the server is active
35
+ except KeyboardInterrupt:
36
+ print("\nShutting down monitor server...")
qulab/monitor/config.py CHANGED
@@ -1,41 +1,66 @@
1
+ """
2
+ QuLab Monitor Configuration Module
3
+
4
+ This module defines the global configuration settings for the QuLab monitor
5
+ application, including:
6
+ - Visual styles and themes
7
+ - Data transformation functions
8
+ - Plot appearance settings
9
+ - Buffer sizes and indices
10
+
11
+ The configuration values are used throughout the monitor application to maintain
12
+ consistent appearance and behavior.
13
+ """
14
+
15
+ from typing import Callable, Dict, List, Tuple, Union
1
16
  import numpy as np
2
17
 
3
- style = '''
18
+ # Qt stylesheet for the application
19
+ STYLE = '''
4
20
  QWidget {
5
21
  font: medium Ubuntu;
6
22
  background-color: #011F2F;
7
23
  font-size: 16px;
8
- font-size: 16px;
9
- color:#FFFFFF;
24
+ color: #FFFFFF;
10
25
  }
11
26
  '''
12
- #
13
- Nroll = 6
14
-
15
- # Format of the data.
16
- forms = {
17
- "mag": lambda w, ang: np.abs(w),
18
- "phase": lambda w, ang: np.angle(w),
19
- "real": lambda w, ang: np.real(w),
20
- "imag": lambda w, ang: np.imag(w),
21
- "rot": lambda w, ang: np.real(np.exp(1j * ang) * np.array(w))
27
+
28
+ # Number of data frames to keep in the rolling buffer
29
+ ROLL_BUFFER_SIZE = 6
30
+
31
+ # Data transformation functions for complex data visualization
32
+ DataTransform = Callable[[Union[np.ndarray, list], float], np.ndarray]
33
+
34
+ TRANSFORMS: Dict[str, DataTransform] = {
35
+ "mag": lambda data, _: np.abs(data),
36
+ "phase": lambda data, _: np.angle(data),
37
+ "real": lambda data, _: np.real(data),
38
+ "imag": lambda data, _: np.imag(data),
39
+ "rot": lambda data, angle: np.real(np.exp(1j * angle) * np.array(data))
22
40
  }
23
- form_keys = list(forms.keys())
24
- #
25
- COL_SEL = (0, 0, 0)
26
- COL_UNSEL = (6, 6, 8)
27
- #
28
-
29
- defualt_colors = [
30
- (200, 0, 0),
31
- (55, 100, 180),
32
- (40, 80, 150),
33
- (30, 50, 110),
34
- (25, 40, 70),
35
- (25, 30, 50),
41
+
42
+ # List of available transformation names
43
+ TRANSFORM_NAMES: List[str] = list(TRANSFORMS.keys())
44
+
45
+ # Colors for selected and unselected states (RGB values)
46
+ COLOR_SELECTED: Tuple[int, int, int] = (0, 0, 0)
47
+ COLOR_UNSELECTED: Tuple[int, int, int] = (6, 6, 8)
48
+
49
+ # Default colors for plot lines (RGB values)
50
+ DEFAULT_COLORS: List[Tuple[int, int, int]] = [
51
+ (200, 0, 0), # Bright red
52
+ (55, 100, 180), # Blue
53
+ (40, 80, 150), # Medium blue
54
+ (30, 50, 110), # Dark blue
55
+ (25, 40, 70), # Navy
56
+ (25, 30, 50), # Dark navy
36
57
  ]
37
58
 
38
- widths = [3, 2, 2, 2, 1, 1]
39
- SymSize = [5, 0, 0, 0, 0, 0]
40
- ridx = list(range(Nroll))
41
- ridx.reverse()
59
+ # Line widths for each plot line
60
+ LINE_WIDTHS: List[int] = [3, 2, 2, 2, 1, 1]
61
+
62
+ # Symbol sizes for each plot line (0 means no symbols)
63
+ SYMBOL_SIZES: List[int] = [5, 0, 0, 0, 0, 0]
64
+
65
+ # Reversed indices for the rolling buffer (newest to oldest)
66
+ ROLL_INDICES: List[int] = list(range(ROLL_BUFFER_SIZE))[::-1]