QuLab 2.0.0__tar.gz → 2.0.1__tar.gz

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.
Files changed (92) hide show
  1. {QuLab-2.0.0 → QuLab-2.0.1}/PKG-INFO +1 -1
  2. {QuLab-2.0.0 → QuLab-2.0.1}/QuLab.egg-info/PKG-INFO +1 -1
  3. {QuLab-2.0.0 → QuLab-2.0.1}/QuLab.egg-info/SOURCES.txt +18 -8
  4. QuLab-2.0.1/QuLab.egg-info/entry_points.txt +2 -0
  5. {QuLab-2.0.0 → QuLab-2.0.1}/pyproject.toml +3 -0
  6. QuLab-2.0.1/qulab/__main__.py +24 -0
  7. QuLab-2.0.1/qulab/monitor/__init__.py +1 -0
  8. QuLab-2.0.1/qulab/monitor/__main__.py +8 -0
  9. QuLab-2.0.0/qulab/monitor/__init__.py → QuLab-2.0.1/qulab/monitor/monitor.py +2 -2
  10. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/scan/base.py +13 -9
  11. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/scan/expression.py +117 -5
  12. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/scan/scanner.py +30 -4
  13. QuLab-2.0.1/qulab/version.py +1 -0
  14. QuLab-2.0.1/qulab/visualization/__init__.py +188 -0
  15. QuLab-2.0.1/qulab/visualization/__main__.py +71 -0
  16. QuLab-2.0.1/qulab/visualization/_autoplot.py +457 -0
  17. QuLab-2.0.1/qulab/visualization/plot_layout.py +408 -0
  18. QuLab-2.0.1/qulab/visualization/plot_seq.py +90 -0
  19. QuLab-2.0.1/qulab/visualization/qdat.py +152 -0
  20. QuLab-2.0.1/qulab/visualization/widgets.py +86 -0
  21. {QuLab-2.0.0 → QuLab-2.0.1}/setup.py +1 -1
  22. QuLab-2.0.0/qulab/monitor/multiploter/__init__.py +0 -1
  23. QuLab-2.0.0/qulab/version.py +0 -1
  24. {QuLab-2.0.0 → QuLab-2.0.1}/LICENSE +0 -0
  25. {QuLab-2.0.0 → QuLab-2.0.1}/MANIFEST.in +0 -0
  26. {QuLab-2.0.0 → QuLab-2.0.1}/QuLab.egg-info/dependency_links.txt +0 -0
  27. {QuLab-2.0.0 → QuLab-2.0.1}/QuLab.egg-info/requires.txt +0 -0
  28. {QuLab-2.0.0 → QuLab-2.0.1}/QuLab.egg-info/top_level.txt +0 -0
  29. {QuLab-2.0.0 → QuLab-2.0.1}/README.md +0 -0
  30. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/__init__.py +0 -0
  31. {QuLab-2.0.0/qulab/monitor/multiploter → QuLab-2.0.1/qulab/monitor}/config.py +0 -0
  32. {QuLab-2.0.0/qulab/monitor/multiploter → QuLab-2.0.1/qulab/monitor}/dataset.py +0 -0
  33. {QuLab-2.0.0/qulab/monitor/multiploter → QuLab-2.0.1/qulab/monitor}/event_queue.py +0 -0
  34. /QuLab-2.0.0/qulab/monitor/multiploter/main.py → /QuLab-2.0.1/qulab/monitor/mainwindow.py +0 -0
  35. {QuLab-2.0.0/qulab/monitor/multiploter → QuLab-2.0.1/qulab/monitor}/ploter.py +0 -0
  36. {QuLab-2.0.0/qulab/monitor/multiploter → QuLab-2.0.1/qulab/monitor}/qt_compat.py +0 -0
  37. {QuLab-2.0.0/qulab/monitor/multiploter → QuLab-2.0.1/qulab/monitor}/toolbar.py +0 -0
  38. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/scan/__init__.py +0 -0
  39. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/scan/dataset.py +0 -0
  40. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/scan/optimize.py +0 -0
  41. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/scan/transforms.py +0 -0
  42. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/scan/utils.py +0 -0
  43. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/__init__.py +0 -0
  44. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/__main__.py +0 -0
  45. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/backend/__init__.py +0 -0
  46. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/backend/redis.py +0 -0
  47. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/base_dataset.py +0 -0
  48. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/chunk.py +0 -0
  49. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/dataset.py +0 -0
  50. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/file.py +0 -0
  51. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/__init__.py +0 -0
  52. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/base.py +0 -0
  53. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/config.py +0 -0
  54. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/file.py +0 -0
  55. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/ipy.py +0 -0
  56. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/models.py +0 -0
  57. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/record.py +0 -0
  58. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/report.py +0 -0
  59. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/models/tag.py +0 -0
  60. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/storage/storage.py +0 -0
  61. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/__init__.py +0 -0
  62. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/chat.py +0 -0
  63. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/device/__init__.py +0 -0
  64. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/device/basedevice.py +0 -0
  65. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/device/loader.py +0 -0
  66. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/device/utils.py +0 -0
  67. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/drivers/FakeInstrument.py +0 -0
  68. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/drivers/__init__.py +0 -0
  69. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/ipy_events.py +0 -0
  70. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/net/__init__.py +0 -0
  71. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/net/bencoder.py +0 -0
  72. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/net/cli.py +0 -0
  73. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/net/dhcp.py +0 -0
  74. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/net/dhcpd.py +0 -0
  75. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/net/kad.py +0 -0
  76. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/net/kcp.py +0 -0
  77. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/net/nginx.py +0 -0
  78. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/progress.py +0 -0
  79. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/__init__.py +0 -0
  80. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/client.py +0 -0
  81. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/exceptions.py +0 -0
  82. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/msgpack.py +0 -0
  83. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/msgpack.pyi +0 -0
  84. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/rpc.py +0 -0
  85. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/serialize.py +0 -0
  86. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/server.py +0 -0
  87. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/socket.py +0 -0
  88. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/utils.py +0 -0
  89. {QuLab-2.0.0 → QuLab-2.0.1}/qulab/sys/rpc/worker.py +0 -0
  90. {QuLab-2.0.0 → QuLab-2.0.1}/setup.cfg +0 -0
  91. {QuLab-2.0.0 → QuLab-2.0.1}/src/qulab.h +0 -0
  92. {QuLab-2.0.0 → QuLab-2.0.1}/tests/test_scan_iter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: QuLab
3
- Version: 2.0.0
3
+ Version: 2.0.1
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: QuLab
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: contral instruments and manage data
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -6,19 +6,22 @@ setup.py
6
6
  QuLab.egg-info/PKG-INFO
7
7
  QuLab.egg-info/SOURCES.txt
8
8
  QuLab.egg-info/dependency_links.txt
9
+ QuLab.egg-info/entry_points.txt
9
10
  QuLab.egg-info/requires.txt
10
11
  QuLab.egg-info/top_level.txt
11
12
  qulab/__init__.py
13
+ qulab/__main__.py
12
14
  qulab/version.py
13
15
  qulab/monitor/__init__.py
14
- qulab/monitor/multiploter/__init__.py
15
- qulab/monitor/multiploter/config.py
16
- qulab/monitor/multiploter/dataset.py
17
- qulab/monitor/multiploter/event_queue.py
18
- qulab/monitor/multiploter/main.py
19
- qulab/monitor/multiploter/ploter.py
20
- qulab/monitor/multiploter/qt_compat.py
21
- qulab/monitor/multiploter/toolbar.py
16
+ qulab/monitor/__main__.py
17
+ qulab/monitor/config.py
18
+ qulab/monitor/dataset.py
19
+ qulab/monitor/event_queue.py
20
+ qulab/monitor/mainwindow.py
21
+ qulab/monitor/monitor.py
22
+ qulab/monitor/ploter.py
23
+ qulab/monitor/qt_compat.py
24
+ qulab/monitor/toolbar.py
22
25
  qulab/scan/__init__.py
23
26
  qulab/scan/base.py
24
27
  qulab/scan/dataset.py
@@ -74,5 +77,12 @@ qulab/sys/rpc/server.py
74
77
  qulab/sys/rpc/socket.py
75
78
  qulab/sys/rpc/utils.py
76
79
  qulab/sys/rpc/worker.py
80
+ qulab/visualization/__init__.py
81
+ qulab/visualization/__main__.py
82
+ qulab/visualization/_autoplot.py
83
+ qulab/visualization/plot_layout.py
84
+ qulab/visualization/plot_seq.py
85
+ qulab/visualization/qdat.py
86
+ qulab/visualization/widgets.py
77
87
  src/qulab.h
78
88
  tests/test_scan_iter.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ qulab = qulab.__main__:main
@@ -41,6 +41,9 @@ dependencies = [
41
41
  ]
42
42
  dynamic = ["version"]
43
43
 
44
+ [project.scripts]
45
+ "qulab" = "qulab.__main__:main"
46
+
44
47
  [project.urls]
45
48
  Homepage = "https://github.com/feihoo87/QuLab"
46
49
  "Bug Reports" = "https://github.com/feihoo87/QuLab/issues"
@@ -0,0 +1,24 @@
1
+ import click
2
+
3
+ from .monitor.__main__ import main as monitor
4
+ from .sys.net.cli import dht
5
+ from .visualization.__main__ import plot
6
+
7
+
8
+ @click.group()
9
+ def main():
10
+ pass
11
+
12
+
13
+ @main.command()
14
+ def hello():
15
+ """Print hello world."""
16
+ click.echo('hello, world')
17
+
18
+
19
+ main.add_command(monitor)
20
+ main.add_command(plot)
21
+ main.add_command(dht)
22
+
23
+ if __name__ == '__main__':
24
+ main()
@@ -0,0 +1 @@
1
+ from .monitor import Monitor, get_monitor
@@ -0,0 +1,8 @@
1
+ import click
2
+
3
+ from .monitor import Monitor
4
+
5
+
6
+ @click.command(name='monitor')
7
+ def main():
8
+ pass
@@ -11,8 +11,8 @@ def main(queue: mp.Queue,
11
11
  ncols: int = 4,
12
12
  minimum_height: int = 400,
13
13
  colors: list[tuple[int, int, int]] = []):
14
- from .multiploter import MainWindow
15
- from .multiploter.qt_compat import QtWidgets
14
+ from .mainwindow import MainWindow
15
+ from .qt_compat import QtWidgets
16
16
 
17
17
  app = QtWidgets.QApplication(sys.argv)
18
18
  main = MainWindow(queue, ncols, minimum_height, colors)
@@ -1,4 +1,3 @@
1
-
2
1
  import inspect
3
2
  import logging
4
3
  import warnings
@@ -7,7 +6,6 @@ from concurrent.futures import Executor, Future
7
6
  from dataclasses import dataclass, field
8
7
  from graphlib import TopologicalSorter
9
8
  from itertools import chain, count
10
-
11
9
  from queue import Empty, Queue
12
10
  from typing import Any, Callable, Iterable, Sequence, Type
13
11
 
@@ -323,20 +321,27 @@ def _args_generator(loops: list,
323
321
  kw = _generate_kwds(keys, current_iters, kwds, i, limit)
324
322
  except StopIteration:
325
323
  break
324
+ if vars:
325
+ vars2 = [
326
+ *vars[:-1],
327
+ tuple([*vars[-1], *local_vars]),
328
+ tuple(kw.keys())
329
+ ]
330
+ else:
331
+ vars2 = [tuple([*local_vars, *kw.keys()])]
326
332
  yield Begin(level=level,
327
333
  pos=pos + (i, ),
328
334
  kwds=kwds | kw,
329
- vars=[*vars, tuple([*local_vars, *kw.keys()])],
335
+ vars=vars2,
330
336
  _pipes=pipes,
331
337
  _trackers=trackers)
332
- yield from _args_generator(
333
- loops, kwds | kw, level + 1, pos + (i, ),
334
- [*vars, tuple([*local_vars, *kw.keys()])], filter, functions,
335
- trackers, pipes, order)
338
+ yield from _args_generator(loops, kwds | kw, level + 1, pos + (i, ),
339
+ vars2, filter, functions, trackers, pipes,
340
+ order)
336
341
  yield End(level=level,
337
342
  pos=pos + (i, ),
338
343
  kwds=kwds | kw,
339
- vars=[*vars, tuple([*local_vars, *kw.keys()])],
344
+ vars=vars2,
340
345
  _pipes=pipes,
341
346
  _trackers=trackers)
342
347
  _feedback(current_iters)
@@ -541,4 +546,3 @@ def scan_iters(loops: dict[str | tuple[str, ...],
541
546
  step.unchanged = i
542
547
  yield step
543
548
  last_step = step
544
-
@@ -8,6 +8,7 @@ from pyparsing import (CaselessKeyword, Combine, Forward, Group, Keyword,
8
8
  alphanums, alphas, delimitedList, nums, oneOf, opAssoc,
9
9
  pyparsing_common, restOfLine, srange, stringEnd,
10
10
  stringStart)
11
+ from scipy import special
11
12
 
12
13
  LPAREN, RPAREN, LBRACK, RBRACK, LBRACE, RBRACE, DOT, TILDE, BANG, PLUS, MINUS = map(
13
14
  Suppress, "()[]{}.~!+-")
@@ -60,15 +61,45 @@ class Env():
60
61
  self.consts = {}
61
62
  self.variables = {}
62
63
  self.refs = {}
64
+ self.functions = {
65
+ 'sin': np.sin,
66
+ 'cos': np.cos,
67
+ 'tan': np.tan,
68
+ 'pi': np.pi,
69
+ 'e': np.e,
70
+ 'log': np.log,
71
+ 'log2': np.log2,
72
+ 'log10': np.log10,
73
+ 'exp': np.exp,
74
+ 'sqrt': np.sqrt,
75
+ 'abs': np.abs,
76
+ 'sinh': np.sinh,
77
+ 'cosh': np.cosh,
78
+ 'tanh': np.tanh,
79
+ 'arcsin': np.arcsin,
80
+ 'arccos': np.arccos,
81
+ 'arctan': np.arctan,
82
+ 'arctan2': np.arctan2,
83
+ 'arcsinh': np.arcsinh,
84
+ 'arccosh': np.arccosh,
85
+ 'arctanh': np.arctanh,
86
+ 'sinc': np.sinc,
87
+ 'sign': np.sign,
88
+ 'heaviside': np.heaviside,
89
+ 'erf': special.erf,
90
+ 'erfc': special.erfc,
91
+ }
63
92
 
64
93
  def __contains__(self, key):
65
- return key in self.consts or key in self.variables or key in self.refs
94
+ return key in self.consts or key in self.variables or key in self.functions or key in self.refs
66
95
 
67
96
  def __getitem__(self, key):
68
97
  if key in self.consts:
69
98
  return self.consts[key]
70
99
  if key in self.variables:
71
100
  return self.variables[key]
101
+ if key in self.functions:
102
+ return self.functions[key]
72
103
  if key in self.refs:
73
104
  return self[self.refs[key]]
74
105
  raise KeyError(f"Key {key} not found")
@@ -110,6 +141,9 @@ class Env():
110
141
  return key in self.consts
111
142
 
112
143
 
144
+ _default_env = Env()
145
+
146
+
113
147
  class Expression():
114
148
 
115
149
  def __init__(self):
@@ -127,33 +161,85 @@ class Expression():
127
161
  raise NotImplementedError
128
162
 
129
163
  def __add__(self, other):
164
+ if isinstance(other, Expression):
165
+ other = other.eval(_default_env)
166
+ if isinstance(other, ConstType) and other == 0:
167
+ return self
130
168
  return BinaryExpression(self, other, operator.add)
131
169
 
132
170
  def __radd__(self, other):
171
+ if isinstance(other, Expression):
172
+ other = other.eval(_default_env)
173
+ if isinstance(other, ConstType) and other == 0:
174
+ return self
133
175
  return BinaryExpression(other, self, operator.add)
134
176
 
135
177
  def __sub__(self, other):
178
+ if isinstance(other, Expression):
179
+ other = other.eval(_default_env)
180
+ if isinstance(other, ConstType) and other == 0:
181
+ return self
136
182
  return BinaryExpression(self, other, operator.sub)
137
183
 
138
184
  def __rsub__(self, other):
185
+ if isinstance(other, Expression):
186
+ other = other.eval(_default_env)
187
+ if isinstance(other, ConstType) and other == 0:
188
+ return -self
139
189
  return BinaryExpression(other, self, operator.sub)
140
190
 
141
191
  def __mul__(self, other):
192
+ if isinstance(other, Expression):
193
+ other = other.eval(_default_env)
194
+ if isinstance(other, ConstType) and other == 0:
195
+ return 0
196
+ if isinstance(other, ConstType) and other == 1:
197
+ return self
198
+ if isinstance(other, ConstType) and other == -1:
199
+ return -self
142
200
  return BinaryExpression(self, other, operator.mul)
143
201
 
144
202
  def __rmul__(self, other):
203
+ if isinstance(other, Expression):
204
+ other = other.eval(_default_env)
205
+ if isinstance(other, ConstType) and other == 0:
206
+ return 0
207
+ if isinstance(other, ConstType) and other == 1:
208
+ return self
209
+ if isinstance(other, ConstType) and other == -1:
210
+ return -self
145
211
  return BinaryExpression(other, self, operator.mul)
146
212
 
147
213
  def __truediv__(self, other):
214
+ if isinstance(other, Expression):
215
+ other = other.eval(_default_env)
216
+ if isinstance(other, ConstType) and other == 1:
217
+ return self
218
+ if isinstance(other, ConstType) and other == -1:
219
+ return -self
148
220
  return BinaryExpression(self, other, operator.truediv)
149
221
 
150
222
  def __rtruediv__(self, other):
223
+ if isinstance(other, Expression):
224
+ other = other.eval(_default_env)
225
+ if isinstance(other, ConstType) and other == 0:
226
+ return 0
151
227
  return BinaryExpression(other, self, operator.truediv)
152
228
 
153
229
  def __pow__(self, other):
230
+ if isinstance(other, Expression):
231
+ other = other.eval(_default_env)
232
+ if isinstance(other, ConstType) and other == 0:
233
+ return 1
234
+ if isinstance(other, ConstType) and other == 1:
235
+ return self
154
236
  return BinaryExpression(self, other, operator.pow)
155
237
 
156
238
  def __rpow__(self, other):
239
+ if isinstance(other, Expression):
240
+ other = other.eval(_default_env)
241
+ if isinstance(other, ConstType) and other == 0:
242
+ return 0
157
243
  return BinaryExpression(other, self, operator.pow)
158
244
 
159
245
  def __neg__(self):
@@ -163,32 +249,52 @@ class Expression():
163
249
  return UnaryExpression(self, operator.pos)
164
250
 
165
251
  def __eq__(self, other):
252
+ if isinstance(other, Expression):
253
+ other = other.eval(_default_env)
166
254
  return BinaryExpression(self, other, operator.eq)
167
255
 
168
256
  def __ne__(self, other):
257
+ if isinstance(other, Expression):
258
+ other = other.eval(_default_env)
169
259
  return BinaryExpression(self, other, operator.ne)
170
260
 
171
261
  def __lt__(self, other):
262
+ if isinstance(other, Expression):
263
+ other = other.eval(_default_env)
172
264
  return BinaryExpression(self, other, operator.lt)
173
265
 
174
266
  def __le__(self, other):
267
+ if isinstance(other, Expression):
268
+ other = other.eval(_default_env)
175
269
  return BinaryExpression(self, other, operator.le)
176
270
 
177
271
  def __gt__(self, other):
272
+ if isinstance(other, Expression):
273
+ other = other.eval(_default_env)
178
274
  return BinaryExpression(self, other, operator.gt)
179
275
 
180
276
  def __ge__(self, other):
277
+ if isinstance(other, Expression):
278
+ other = other.eval(_default_env)
181
279
  return BinaryExpression(self, other, operator.ge)
182
280
 
183
281
  def __getitem__(self, other):
282
+ if isinstance(other, Expression):
283
+ other = other.eval(_default_env)
184
284
  return ObjectMethod(self, '__getitem__', other)
185
285
 
186
286
  def __getattr__(self, other):
287
+ if isinstance(other, Expression):
288
+ other = other.eval(_default_env)
187
289
  return ObjectMethod(self, '__getattr__', other)
188
290
 
189
291
  def __call__(self, *args):
292
+ args = [
293
+ o.eval(_default_env) if isinstance(o, Expression) else o
294
+ for o in args
295
+ ]
190
296
  return ObjectMethod(self, '__call__', *args)
191
-
297
+
192
298
  def __round__(self, n=None):
193
299
  return self
194
300
 
@@ -243,7 +349,7 @@ class UnaryExpression(Expression):
243
349
  return self.op(self.a.d(x))
244
350
  else:
245
351
  return 0
246
-
352
+
247
353
  def __repr__(self) -> str:
248
354
  return f"{self.op.__name__}({self.a!r})"
249
355
 
@@ -300,7 +406,7 @@ class BinaryExpression(Expression):
300
406
  return 0
301
407
  else:
302
408
  return 0
303
-
409
+
304
410
  def __repr__(self) -> str:
305
411
  return f"({self.a!r} {self.op.__name__} {self.b!r})"
306
412
 
@@ -333,6 +439,12 @@ class ObjectMethod(Expression):
333
439
  return ObjectMethod(obj, self.method, *args)
334
440
  else:
335
441
  return getattr(obj, self.method)(*args)
442
+
443
+ def __repr__(self):
444
+ if self.method == '__call__':
445
+ return f"{self.obj!r}({', '.join(map(repr, self.args))})"
446
+ else:
447
+ return f"{self.obj!r}.{self.method}({', '.join(map(repr, self.args))})"
336
448
 
337
449
 
338
450
  class Symbol(Expression):
@@ -355,6 +467,6 @@ class Symbol(Expression):
355
467
  return 1
356
468
  else:
357
469
  return 0
358
-
470
+
359
471
  def __repr__(self) -> str:
360
472
  return self.name
@@ -1,4 +1,5 @@
1
1
  import ast
2
+ import itertools
2
3
 
3
4
  import numpy as np
4
5
 
@@ -73,6 +74,19 @@ class Optimizer():
73
74
  **self.kwds)
74
75
 
75
76
 
77
+ class Action():
78
+
79
+ __slots__ = ('name', 'args', 'kwds')
80
+
81
+ def __init__(self, name, *args, **kwds):
82
+ self.name = name
83
+ self.args = args
84
+ self.kwds = kwds
85
+
86
+ def __repr__(self):
87
+ return f"Action({self.name!r}, {self.args}, {self.kwds})"
88
+
89
+
76
90
  class Scan():
77
91
 
78
92
  def __new__(cls, *args, mixin=None, **kwds):
@@ -99,6 +113,8 @@ class Scan():
99
113
  self.filter = None
100
114
  self.scan_info = {'loops': {}}
101
115
  self._tmp = {}
116
+ self.actions = {}
117
+ self.iteration = 0
102
118
 
103
119
  @property
104
120
  def name(self):
@@ -114,12 +130,12 @@ class Scan():
114
130
  return default
115
131
 
116
132
  def set(self, key, value):
117
- print(f"Set {key} to {value}")
133
+ self.add_action(Action('set', key, value))
118
134
 
119
135
  def _mapping(self, key, value):
120
136
  tmpkey = f"__tmp_{self._mapping_i}__"
121
137
  self._mapping_i += 1
122
- self[tmpkey] = value
138
+ self.__setitem(tmpkey, value)
123
139
  self.mapping[key] = tmpkey
124
140
 
125
141
  def __setitem__(self, key, value):
@@ -219,17 +235,27 @@ class Scan():
219
235
  self.assemble()
220
236
  for step in self.scan():
221
237
  for k, v in self.mapping.items():
222
- self.set(k, step.kwds[v])
238
+ if v in set(
239
+ itertools.chain.from_iterable(
240
+ step.vars[step.unchanged:])
241
+ ) or step.iteration == 0:
242
+ self.set(k, step.kwds[v])
223
243
  self.process(step)
224
244
 
225
245
  def process(self, step):
226
- print(step.kwds)
246
+ for k, v in step.kwds.items():
247
+ if not k.startswith('__tmp_') and not k.startswith('__'):
248
+ self.add_action(Action('write', k, v))
227
249
 
228
250
  def scan(self):
229
251
  for step in scan_iters(**self.scan_info):
230
252
  for k, v in self.mapping.items():
231
253
  step.kwds[k] = step.kwds[v]
232
254
  yield step
255
+ self.iteration += 1
256
+
257
+ def add_action(self, action: Action):
258
+ self.actions.setdefault(self.iteration, []).append(action)
233
259
 
234
260
  def run(self, dry_run=False):
235
261
  pass
@@ -0,0 +1 @@
1
+ __version__ = "2.0.1"
@@ -0,0 +1,188 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+
4
+ from ._autoplot import autoplot
5
+
6
+
7
+ def plotLine(c0, c1, ax, **kwargs):
8
+ t = np.linspace(0, 1, 11)
9
+ c = (c1 - c0) * t + c0
10
+ ax.plot(c.real, c.imag, **kwargs)
11
+
12
+
13
+ def plotCircle(c0, r, ax, **kwargs):
14
+ t = np.linspace(0, 1, 1001) * 2 * np.pi
15
+ s = c0 + r * np.exp(1j * t)
16
+ ax.plot(s.real, s.imag, **kwargs)
17
+
18
+
19
+ def plotEllipse(c0, a, b, phi, ax, **kwargs):
20
+ t = np.linspace(0, 1, 1001) * 2 * np.pi
21
+ c = np.exp(1j * t)
22
+ s = c0 + (c.real * a + 1j * c.imag * b) * np.exp(1j * phi)
23
+ ax.plot(s.real, s.imag, **kwargs)
24
+
25
+
26
+ def plotDistribution(s0,
27
+ s1,
28
+ fig=None,
29
+ axes=None,
30
+ info=None,
31
+ hotThresh=10000,
32
+ logy=False):
33
+ from waveforms.math.fit import get_threshold_info, mult_gaussian_pdf
34
+
35
+ if info is None:
36
+ info = get_threshold_info(s0, s1)
37
+ else:
38
+ info = get_threshold_info(s0, s1, info['threshold'], info['phi'])
39
+ thr, phi = info['threshold'], info['phi']
40
+ # visibility, p0, p1 = info['visibility']
41
+ # print(
42
+ # f"thr={thr:.6f}, phi={phi:.6f}, visibility={visibility:.3f}, {p0}, {1-p1}"
43
+ # )
44
+
45
+ if axes is not None:
46
+ ax1, ax2 = axes
47
+ else:
48
+ if fig is None:
49
+ fig = plt.figure()
50
+ ax1 = fig.add_subplot(121)
51
+ ax2 = fig.add_subplot(122)
52
+
53
+ if (len(s0) + len(s1)) < hotThresh:
54
+ ax1.plot(np.real(s0), np.imag(s0), '.', alpha=0.2)
55
+ ax1.plot(np.real(s1), np.imag(s1), '.', alpha=0.2)
56
+ else:
57
+ _, *bins = np.histogram2d(np.real(np.hstack([s0, s1])),
58
+ np.imag(np.hstack([s0, s1])),
59
+ bins=50)
60
+
61
+ H0, *_ = np.histogram2d(np.real(s0),
62
+ np.imag(s0),
63
+ bins=bins,
64
+ density=True)
65
+ H1, *_ = np.histogram2d(np.real(s1),
66
+ np.imag(s1),
67
+ bins=bins,
68
+ density=True)
69
+ vlim = max(np.max(np.abs(H0)), np.max(np.abs(H1)))
70
+
71
+ ax1.imshow(H1.T - H0.T,
72
+ alpha=(np.fmax(H0.T, H1.T) / vlim).clip(0, 1),
73
+ interpolation='nearest',
74
+ origin='lower',
75
+ cmap='coolwarm',
76
+ vmin=-vlim,
77
+ vmax=vlim,
78
+ extent=(bins[0][0], bins[0][-1], bins[1][0], bins[1][-1]))
79
+
80
+ ax1.axis('equal')
81
+ ax1.set_xticks([])
82
+ ax1.set_yticks([])
83
+ for s in ax1.spines.values():
84
+ s.set_visible(False)
85
+
86
+ # c0, c1 = info['center']
87
+ # a0, b0, a1, b1 = info['std']
88
+ params = info['params']
89
+ r0, i0, r1, i1 = params[0][0], params[1][0], params[0][1], params[1][1]
90
+ a0, b0, a1, b1 = params[0][2], params[1][2], params[0][3], params[1][3]
91
+ c0 = (r0 + 1j * i0) * np.exp(1j * phi)
92
+ c1 = (r1 + 1j * i1) * np.exp(1j * phi)
93
+ phi0 = phi + params[0][6]
94
+ phi1 = phi + params[1][6]
95
+ plotEllipse(c0, 2 * a0, 2 * b0, phi0, ax1)
96
+ plotEllipse(c1, 2 * a1, 2 * b1, phi1, ax1)
97
+
98
+ im0, im1 = info['idle']
99
+ lim = min(im0.min(), im1.min()), max(im0.max(), im1.max())
100
+ t = (np.linspace(lim[0], lim[1], 3) + 1j * thr) * np.exp(-1j * phi)
101
+ ax1.plot(t.imag, t.real, 'k--')
102
+
103
+ ax1.plot(np.real(c0), np.imag(c0), 'o', color='C3')
104
+ ax1.plot(np.real(c1), np.imag(c1), 'o', color='C4')
105
+
106
+ re0, re1 = info['signal']
107
+ x, a, b, c = info['cdf']
108
+
109
+ xrange = (min(re0.min(), re1.min()), max(re0.max(), re1.max()))
110
+
111
+ n0, bins0, *_ = ax2.hist(re0, bins=80, range=xrange, alpha=0.5)
112
+ n1, bins1, *_ = ax2.hist(re1, bins=80, range=xrange, alpha=0.5)
113
+
114
+ x_range = np.linspace(x.min(), x.max(), 1001)
115
+ *_, cov0, cov1 = info['std']
116
+ ax2.plot(
117
+ x_range,
118
+ np.sum(n0) * (bins0[1] - bins0[0]) *
119
+ mult_gaussian_pdf(x_range, [r0, r1], [
120
+ np.sqrt(cov0[0, 0]), np.sqrt(cov1[0, 0])
121
+ ], [params[0][4], 1 - params[0][4]]))
122
+ ax2.plot(
123
+ x_range,
124
+ np.sum(n1) * (bins1[1] - bins1[0]) *
125
+ mult_gaussian_pdf(x_range, [r0, r1], [
126
+ np.sqrt(cov0[0, 0]), np.sqrt(cov1[0, 0])
127
+ ], [params[0][5], 1 - params[0][5]]))
128
+ ax2.set_ylabel('Count')
129
+ ax2.set_xlabel('Projection Axes')
130
+ if logy:
131
+ ax2.set_yscale('log')
132
+ ax2.set_ylim(0.1, max(np.sum(n0), np.sum(n1)))
133
+
134
+ ax3 = ax2.twinx()
135
+ ax3.plot(x, a, '--', lw=1, color='C0')
136
+ ax3.plot(x, b, '--', lw=1, color='C1')
137
+ ax3.plot(x, c, 'k--', alpha=0.5, lw=1)
138
+ ax3.set_ylim(0, 1.1)
139
+ ax3.vlines(thr, 0, 1.1, 'k', alpha=0.5)
140
+ ax3.set_ylabel('Integral Probability')
141
+
142
+ return info
143
+
144
+
145
+ ALLXYSeq = [('I', 'I'), ('X', 'X'), ('Y', 'Y'), ('X', 'Y'), ('Y', 'X'),
146
+ ('X/2', 'I'), ('Y/2', 'I'), ('X/2', 'Y/2'), ('Y/2', 'X/2'),
147
+ ('X/2', 'Y'), ('Y/2', 'X'), ('X', 'Y/2'), ('Y', 'X/2'),
148
+ ('X/2', 'X'), ('X', 'X/2'), ('Y/2', 'Y'), ('Y', 'Y/2'), ('X', 'I'),
149
+ ('Y', 'I'), ('X/2', 'X/2'), ('Y/2', 'Y/2')]
150
+
151
+
152
+ def plotALLXY(data, ax=None):
153
+ assert len(data) % len(ALLXYSeq) == 0
154
+
155
+ if ax is None:
156
+ ax = plt.gca()
157
+
158
+ ax.plot(np.array(data), 'o-')
159
+ repeat = len(data) // len(ALLXYSeq)
160
+ ax.set_xticks(np.arange(len(ALLXYSeq)) * repeat + 0.5 * (repeat - 1))
161
+ ax.set_xticklabels([','.join(seq) for seq in ALLXYSeq], rotation=60)
162
+ ax.grid(which='major')
163
+
164
+
165
+ def plot_mat(rho, title='$\\chi$', cmap='coolwarm'):
166
+ lim = np.abs(rho).max()
167
+ N = rho.shape[0]
168
+
169
+ fig = plt.figure(figsize=(6, 4))
170
+ fig.suptitle(title)
171
+
172
+ ax1 = plt.subplot(121)
173
+ cax1 = ax1.imshow(rho.real, vmin=-lim, vmax=lim, cmap=cmap)
174
+ ax1.set_title('Re')
175
+ ax1.set_xticks(np.arange(N))
176
+ ax1.set_yticks(np.arange(N))
177
+
178
+ ax2 = plt.subplot(122)
179
+ cax2 = ax2.imshow(rho.imag, vmin=-lim, vmax=lim, cmap=cmap)
180
+ ax2.set_title('Im')
181
+ ax2.set_xticks(np.arange(N))
182
+ ax2.set_yticks(np.arange(N))
183
+
184
+ plt.subplots_adjust(bottom=0.2, right=0.9, top=0.95)
185
+
186
+ cbar_ax = fig.add_axes([0.15, 0.15, 0.7, 0.05])
187
+ cb = fig.colorbar(cax1, cax=cbar_ax, orientation='horizontal')
188
+ plt.show()