QuLab 2.10.10__cp313-cp313-macosx_10_13_universal2.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.
Files changed (107) hide show
  1. qulab/__init__.py +33 -0
  2. qulab/__main__.py +4 -0
  3. qulab/cli/__init__.py +0 -0
  4. qulab/cli/commands.py +30 -0
  5. qulab/cli/config.py +170 -0
  6. qulab/cli/decorators.py +28 -0
  7. qulab/dicttree.py +523 -0
  8. qulab/executor/__init__.py +5 -0
  9. qulab/executor/analyze.py +188 -0
  10. qulab/executor/cli.py +434 -0
  11. qulab/executor/load.py +563 -0
  12. qulab/executor/registry.py +185 -0
  13. qulab/executor/schedule.py +543 -0
  14. qulab/executor/storage.py +615 -0
  15. qulab/executor/template.py +259 -0
  16. qulab/executor/utils.py +194 -0
  17. qulab/expression.py +827 -0
  18. qulab/fun.cpython-313-darwin.so +0 -0
  19. qulab/monitor/__init__.py +1 -0
  20. qulab/monitor/__main__.py +8 -0
  21. qulab/monitor/config.py +41 -0
  22. qulab/monitor/dataset.py +77 -0
  23. qulab/monitor/event_queue.py +54 -0
  24. qulab/monitor/mainwindow.py +234 -0
  25. qulab/monitor/monitor.py +115 -0
  26. qulab/monitor/ploter.py +123 -0
  27. qulab/monitor/qt_compat.py +16 -0
  28. qulab/monitor/toolbar.py +265 -0
  29. qulab/scan/__init__.py +2 -0
  30. qulab/scan/curd.py +221 -0
  31. qulab/scan/models.py +554 -0
  32. qulab/scan/optimize.py +76 -0
  33. qulab/scan/query.py +387 -0
  34. qulab/scan/record.py +603 -0
  35. qulab/scan/scan.py +1166 -0
  36. qulab/scan/server.py +450 -0
  37. qulab/scan/space.py +213 -0
  38. qulab/scan/utils.py +234 -0
  39. qulab/storage/__init__.py +0 -0
  40. qulab/storage/__main__.py +51 -0
  41. qulab/storage/backend/__init__.py +0 -0
  42. qulab/storage/backend/redis.py +204 -0
  43. qulab/storage/base_dataset.py +352 -0
  44. qulab/storage/chunk.py +60 -0
  45. qulab/storage/dataset.py +127 -0
  46. qulab/storage/file.py +273 -0
  47. qulab/storage/models/__init__.py +22 -0
  48. qulab/storage/models/base.py +4 -0
  49. qulab/storage/models/config.py +28 -0
  50. qulab/storage/models/file.py +89 -0
  51. qulab/storage/models/ipy.py +58 -0
  52. qulab/storage/models/models.py +88 -0
  53. qulab/storage/models/record.py +161 -0
  54. qulab/storage/models/report.py +22 -0
  55. qulab/storage/models/tag.py +93 -0
  56. qulab/storage/storage.py +95 -0
  57. qulab/sys/__init__.py +2 -0
  58. qulab/sys/chat.py +688 -0
  59. qulab/sys/device/__init__.py +3 -0
  60. qulab/sys/device/basedevice.py +255 -0
  61. qulab/sys/device/loader.py +86 -0
  62. qulab/sys/device/utils.py +79 -0
  63. qulab/sys/drivers/FakeInstrument.py +68 -0
  64. qulab/sys/drivers/__init__.py +0 -0
  65. qulab/sys/ipy_events.py +125 -0
  66. qulab/sys/net/__init__.py +0 -0
  67. qulab/sys/net/bencoder.py +205 -0
  68. qulab/sys/net/cli.py +169 -0
  69. qulab/sys/net/dhcp.py +543 -0
  70. qulab/sys/net/dhcpd.py +176 -0
  71. qulab/sys/net/kad.py +1142 -0
  72. qulab/sys/net/kcp.py +192 -0
  73. qulab/sys/net/nginx.py +194 -0
  74. qulab/sys/progress.py +190 -0
  75. qulab/sys/rpc/__init__.py +0 -0
  76. qulab/sys/rpc/client.py +0 -0
  77. qulab/sys/rpc/exceptions.py +96 -0
  78. qulab/sys/rpc/msgpack.py +1052 -0
  79. qulab/sys/rpc/msgpack.pyi +41 -0
  80. qulab/sys/rpc/router.py +35 -0
  81. qulab/sys/rpc/rpc.py +412 -0
  82. qulab/sys/rpc/serialize.py +139 -0
  83. qulab/sys/rpc/server.py +29 -0
  84. qulab/sys/rpc/socket.py +29 -0
  85. qulab/sys/rpc/utils.py +25 -0
  86. qulab/sys/rpc/worker.py +0 -0
  87. qulab/sys/rpc/zmq_socket.py +227 -0
  88. qulab/tools/__init__.py +0 -0
  89. qulab/tools/connection_helper.py +39 -0
  90. qulab/typing.py +2 -0
  91. qulab/utils.py +95 -0
  92. qulab/version.py +1 -0
  93. qulab/visualization/__init__.py +188 -0
  94. qulab/visualization/__main__.py +71 -0
  95. qulab/visualization/_autoplot.py +464 -0
  96. qulab/visualization/plot_circ.py +319 -0
  97. qulab/visualization/plot_layout.py +408 -0
  98. qulab/visualization/plot_seq.py +242 -0
  99. qulab/visualization/qdat.py +152 -0
  100. qulab/visualization/rot3d.py +23 -0
  101. qulab/visualization/widgets.py +86 -0
  102. qulab-2.10.10.dist-info/METADATA +110 -0
  103. qulab-2.10.10.dist-info/RECORD +107 -0
  104. qulab-2.10.10.dist-info/WHEEL +5 -0
  105. qulab-2.10.10.dist-info/entry_points.txt +2 -0
  106. qulab-2.10.10.dist-info/licenses/LICENSE +21 -0
  107. qulab-2.10.10.dist-info/top_level.txt +1 -0
@@ -0,0 +1,408 @@
1
+ import functools
2
+ import operator
3
+
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+ from matplotlib import cm
7
+ from matplotlib.colors import Normalize
8
+
9
+ layout_example = {
10
+ 'qubits': {
11
+ 'Q0': {
12
+ 'pos': (0, 1)
13
+ },
14
+ 'Q1': {
15
+ 'pos': (1, 0)
16
+ },
17
+ 'Q2': {
18
+ 'pos': (0, -1)
19
+ },
20
+ 'Q3': {
21
+ 'pos': (-1, 0)
22
+ }
23
+ },
24
+ 'couplers': {
25
+ 'C0': {
26
+ 'qubits': ['Q0', 'Q1'],
27
+ },
28
+ 'C1': {
29
+ 'qubits': ['Q1', 'Q2'],
30
+ },
31
+ 'C2': {
32
+ 'qubits': ['Q2', 'Q3'],
33
+ },
34
+ 'C3': {
35
+ 'qubits': ['Q0', 'Q3'],
36
+ }
37
+ }
38
+ }
39
+
40
+
41
+ def complete_layout(layout):
42
+ for c in layout['couplers']:
43
+ qubits = layout['couplers'][c]['qubits']
44
+ for q in qubits:
45
+ if q not in layout['qubits']:
46
+ raise ValueError('qubit {} not found'.format(q))
47
+ if 'couplers' not in layout['qubits'][q]:
48
+ layout['qubits'][q]['couplers'] = []
49
+ if c not in layout['qubits'][q]['couplers']:
50
+ layout['qubits'][q]['couplers'].append(c)
51
+ return layout
52
+
53
+
54
+ def get_shared_coupler(layout, q1, q2):
55
+ for c in layout['qubits'][q1]['couplers']:
56
+ if q2 in layout['couplers'][c]['qubits']:
57
+ return c
58
+ return None
59
+
60
+
61
+ def get_neighbours(layout,
62
+ qubit_or_coupler,
63
+ distance=1,
64
+ type='qubit',
65
+ inrange=False):
66
+
67
+ def _qubits(couplers):
68
+ ret = set()
69
+ for c in couplers:
70
+ ret = ret | set(layout['couplers'][c]['qubits'])
71
+ return ret
72
+
73
+ def _couplers(qubits):
74
+ ret = set()
75
+ for q in qubits:
76
+ ret = ret | set(layout['qubits'][q]['couplers'])
77
+ return ret
78
+
79
+ couplers = []
80
+ neighbors = []
81
+
82
+ if qubit_or_coupler in layout['qubits']:
83
+ couplers.append(set(layout['qubits'][qubit_or_coupler]['couplers']))
84
+ neighbors.append(_qubits(couplers[0]) - {qubit_or_coupler})
85
+ elif qubit_or_coupler in layout['couplers']:
86
+ if type == 'coupler':
87
+ distance += 1
88
+ neighbors.append(set(layout['couplers'][qubit_or_coupler]['qubits']))
89
+ couplers.append({qubit_or_coupler})
90
+ else:
91
+ raise ValueError(f'qubit or coupler {qubit_or_coupler!r} not found')
92
+ distance -= 1
93
+
94
+ while distance > 0:
95
+ couplers.append(_couplers(neighbors[-1]) - couplers[-1])
96
+ neighbors.append(_qubits(couplers[-1]) - neighbors[-1])
97
+ distance -= 1
98
+
99
+ if type == 'qubit':
100
+ if inrange:
101
+ return list(functools.reduce(operator.or_, neighbors, set()))
102
+ else:
103
+ return list(neighbors[-1])
104
+ elif type == 'coupler':
105
+ if inrange:
106
+ if qubit_or_coupler in couplers[0]:
107
+ couplers = couplers[1:]
108
+ return list(functools.reduce(operator.or_, couplers, set()))
109
+ else:
110
+ return list(couplers[-1])
111
+ else:
112
+ raise ValueError("type must be 'qubit' or 'coupler'")
113
+
114
+
115
+ def plot_range(ax,
116
+ path,
117
+ text='',
118
+ color=None,
119
+ text_color='k',
120
+ bounder_color='k',
121
+ lw=0.5,
122
+ fontsize=9):
123
+ x, y = path
124
+ center = x.mean(), y.mean()
125
+
126
+ if color:
127
+ ax.fill(x, y, color=color, lw=0)
128
+
129
+ if lw is not None and lw > 0:
130
+ ax.plot(np.hstack([x, [x[0]]]),
131
+ np.hstack([y, [y[0]]]),
132
+ color=bounder_color,
133
+ lw=lw)
134
+
135
+ if text:
136
+ ax.text(center[0],
137
+ center[1],
138
+ text,
139
+ ha='center',
140
+ va='center',
141
+ color=text_color,
142
+ fontsize=fontsize)
143
+
144
+
145
+ def circle_path(pos, r, n=40):
146
+ x, y = pos
147
+ t = 2 * np.pi * np.linspace(0, 1, n, endpoint=False)
148
+ xx = r * np.cos(t) + x
149
+ yy = r * np.sin(t) + y
150
+ return xx, yy
151
+
152
+
153
+ def circle_link_path(pos1, pos2, r1, r2, width, n=20):
154
+ width = min(2 * max(r1, r2), width)
155
+
156
+ x1, y1 = pos1
157
+ x2, y2 = pos2
158
+
159
+ phi = np.arctan2(y2 - y1, x2 - x1)
160
+
161
+ theta1 = np.arcsin(width / 2 / r1)
162
+ theta2 = np.arcsin(width / 2 / r2)
163
+
164
+ t = np.linspace(-theta1, theta1, n) + phi
165
+ xx1 = r1 * np.cos(t) + x1
166
+ yy1 = r1 * np.sin(t) + y1
167
+
168
+ t = np.linspace(-theta2, theta2, n) + phi + np.pi
169
+ xx2 = r2 * np.cos(t) + x2
170
+ yy2 = r2 * np.sin(t) + y2
171
+
172
+ return np.hstack([xx2[-1], xx1,
173
+ xx2[:-1]]), np.hstack([yy2[-1], yy1, yy2[:-1]])
174
+
175
+
176
+ def circle_half_directed_link_path(pos1, pos2, r1, r2, width, n=20):
177
+ width = min(max(r1, r2), width)
178
+
179
+ x1, y1 = pos1
180
+ x2, y2 = pos2
181
+
182
+ phi = np.arctan2(y2 - y1, x2 - x1)
183
+
184
+ theta1 = np.arcsin(width / r1)
185
+ theta2 = np.arcsin(width / r2)
186
+
187
+ t = np.linspace(0.2 * theta1, theta1, n) + phi
188
+ xx1 = r1 * np.cos(t) + x1
189
+ yy1 = r1 * np.sin(t) + y1
190
+
191
+ t = np.linspace(-theta2, -0.2 * theta2, n) + phi + np.pi
192
+ xx2 = r2 * np.cos(t) + x2
193
+ yy2 = r2 * np.sin(t) + y2
194
+
195
+ v = (xx2[0] - xx1[-1]) + 1j * (yy2[0] - yy1[-1])
196
+ c = (xx2[0] + xx1[-1]) / 2 + 1j * (yy2[0] + yy1[-1]) / 2
197
+
198
+ a = np.array([1 / 6, 1 / 12]) + 1j * np.array([0, 0.4 * width / np.abs(v)])
199
+ a = a * v + c
200
+
201
+ return np.hstack([xx2[-1], xx1, a.real,
202
+ xx2[:-1]]), np.hstack([yy2[-1], yy1, a.imag, yy2[:-1]])
203
+
204
+
205
+ def draw(layout, ax=None, qubit_cbar=True, coupler_cbar=True, origin='upper'):
206
+ if ax is None:
207
+ ax = plt.gca()
208
+
209
+ for qubit in layout['qubits'].values():
210
+ pos = qubit['pos']
211
+ if origin == 'upper':
212
+ pos = pos[0], -pos[1]
213
+ path = circle_path(pos, qubit.get('radius', 0.5))
214
+ plot_range(ax,
215
+ path,
216
+ qubit.get('text', ''),
217
+ qubit.get('color', None),
218
+ lw=qubit.get('lw', 0.5),
219
+ fontsize=qubit.get('fontsize', 9),
220
+ text_color=qubit.get('text_color', 'k'),
221
+ bounder_color=qubit.get('bounder_color', 'k'))
222
+
223
+ for coupler in layout['couplers'].values():
224
+ q1, q2 = coupler['qubits']
225
+ pos1 = layout['qubits'][q1]['pos']
226
+ pos2 = layout['qubits'][q2]['pos']
227
+ if origin == 'upper':
228
+ pos1 = pos1[0], -pos1[1]
229
+ pos2 = pos2[0], -pos2[1]
230
+ r1 = layout['qubits'][q1].get('radius', 0.5)
231
+ r2 = layout['qubits'][q2].get('radius', 0.5)
232
+ width = coupler.get('width', 0.5)
233
+ lw = coupler.get('lw', 0.5)
234
+
235
+ path = circle_link_path(pos1, pos2, r1, r2, width)
236
+ plot_range(ax,
237
+ path,
238
+ coupler.get('text', ''),
239
+ color=coupler.get('color', None),
240
+ lw=0,
241
+ fontsize=coupler.get('fontsize', 9),
242
+ text_color=coupler.get('text_color', 'k'))
243
+ if lw > 0:
244
+ x, y = circle_link_path(pos1, pos2, r1, r2, width, n=2)
245
+ ax.plot(x[:2],
246
+ y[:2],
247
+ lw=lw,
248
+ color=coupler.get('bounder_color', 'k'))
249
+ ax.plot(x[2:],
250
+ y[2:],
251
+ lw=lw,
252
+ color=coupler.get('bounder_color', 'k'))
253
+
254
+ ax.axis('equal')
255
+ ax.set_axis_off()
256
+
257
+ if qubit_cbar and layout['__colorbar__']['qubit']['norm'] is not None:
258
+ cbar = plt.colorbar(cm.ScalarMappable(
259
+ norm=layout['__colorbar__']['qubit']['norm'],
260
+ cmap=layout['__colorbar__']['qubit']['cmap']),
261
+ ax=ax,
262
+ location='bottom',
263
+ orientation='horizontal',
264
+ pad=0.01,
265
+ shrink=0.5)
266
+ cbar.set_label(layout['__colorbar__']['qubit']['label'])
267
+ if coupler_cbar and layout['__colorbar__']['coupler']['norm'] is not None:
268
+ cbar = plt.colorbar(cm.ScalarMappable(
269
+ norm=layout['__colorbar__']['coupler']['norm'],
270
+ cmap=layout['__colorbar__']['coupler']['cmap']),
271
+ ax=ax,
272
+ location='bottom',
273
+ orientation='horizontal',
274
+ pad=0.01,
275
+ shrink=0.5)
276
+ cbar.set_label(layout['__colorbar__']['coupler']['label'])
277
+
278
+
279
+ def get_norm(params, elms, vmin=None, vmax=None):
280
+ data = []
281
+ for elm in elms:
282
+ if elm in params:
283
+ if isinstance(params[elm], (int, float)):
284
+ data.append(params[elm])
285
+ elif 'value' in params[elm] and params[elm]['value'] is not None:
286
+ data.append(params[elm]['value'])
287
+ if data:
288
+ if vmin is None:
289
+ vmin = min(data)
290
+ if vmax is None:
291
+ vmax = max(data)
292
+ return Normalize(vmin=vmin, vmax=vmax)
293
+ else:
294
+ return None
295
+
296
+
297
+ def fill_layout(layout,
298
+ params,
299
+ qubit_size=0.5,
300
+ coupler_size=0.5,
301
+ qubit_fontsize=9,
302
+ coupler_fontsize=9,
303
+ qubit_color=None,
304
+ coupler_color=None,
305
+ qubit_cmap='hot',
306
+ qubit_vmax=None,
307
+ qubit_vmin=None,
308
+ qubit_norm=None,
309
+ coupler_cmap='binary',
310
+ coupler_vmax=None,
311
+ coupler_vmin=None,
312
+ coupler_norm=None,
313
+ bounder_color='k',
314
+ lw=0.5):
315
+
316
+ qubit_cmap = plt.get_cmap(qubit_cmap)
317
+ coupler_cmap = plt.get_cmap(coupler_cmap)
318
+
319
+ if qubit_norm is None:
320
+ qubit_norm = get_norm(params,
321
+ layout['qubits'].keys(),
322
+ vmin=qubit_vmin,
323
+ vmax=qubit_vmax)
324
+ if coupler_norm is None:
325
+ coupler_norm = get_norm(params,
326
+ layout['couplers'].keys(),
327
+ vmin=coupler_vmin,
328
+ vmax=coupler_vmax)
329
+ layout['__colorbar__'] = {
330
+ 'coupler': {
331
+ 'cmap': coupler_cmap,
332
+ 'norm': coupler_norm,
333
+ 'label': ''
334
+ },
335
+ 'qubit': {
336
+ 'cmap': qubit_cmap,
337
+ 'norm': qubit_norm,
338
+ 'label': ''
339
+ }
340
+ }
341
+
342
+ for qubit in layout['qubits']:
343
+ layout['qubits'][qubit]['radius'] = qubit_size
344
+ layout['qubits'][qubit]['fontsize'] = qubit_fontsize
345
+ if qubit in params:
346
+ layout['qubits'][qubit]['lw'] = 0
347
+ if not isinstance(params[qubit], dict):
348
+ params[qubit] = {'value': params[qubit]}
349
+ if 'color' in params[qubit]:
350
+ layout['qubits'][qubit]['color'] = params[qubit]['color']
351
+ elif 'value' in params[qubit] and params[qubit][
352
+ 'value'] is not None:
353
+ layout['qubits'][qubit]['color'] = qubit_cmap(
354
+ qubit_norm(params[qubit]['value']))
355
+ else:
356
+ layout['qubits'][qubit]['color'] = qubit_color
357
+ if qubit_color is None:
358
+ layout['qubits'][qubit]['lw'] = lw
359
+ layout['qubits'][qubit]['radius'] = params[qubit].get(
360
+ 'radius', qubit_size)
361
+ layout['qubits'][qubit]['fontsize'] = params[qubit].get(
362
+ 'fontsize', qubit_fontsize)
363
+ layout['qubits'][qubit]['text'] = params[qubit].get('text', '')
364
+ layout['qubits'][qubit]['text_color'] = params[qubit].get(
365
+ 'text_color', 'k')
366
+ else:
367
+ layout['qubits'][qubit]['color'] = qubit_color
368
+ if qubit_color is None:
369
+ layout['qubits'][qubit]['lw'] = lw
370
+ else:
371
+ layout['qubits'][qubit]['lw'] = 0
372
+ layout['qubits'][qubit]['bounder_color'] = bounder_color
373
+
374
+ for coupler in layout['couplers']:
375
+ layout['couplers'][coupler]['width'] = coupler_size
376
+ layout['couplers'][coupler]['fontsize'] = coupler_fontsize
377
+ layout['couplers'][coupler]['bounder_color'] = bounder_color
378
+ if coupler in params:
379
+ layout['couplers'][coupler]['lw'] = 0
380
+ if not isinstance(params[coupler], dict):
381
+ params[coupler] = {'value': params[coupler]}
382
+ if 'color' in params[coupler]:
383
+ layout['couplers'][coupler]['color'] = params[coupler]['color']
384
+ elif 'value' in params[coupler] and params[coupler][
385
+ 'value'] is not None:
386
+ layout['couplers'][coupler]['color'] = coupler_cmap(
387
+ coupler_norm(params[coupler]['value']))
388
+ else:
389
+ layout['couplers'][coupler]['color'] = coupler_color
390
+ if coupler_color is None:
391
+ layout['couplers'][coupler]['lw'] = lw
392
+ layout['couplers'][coupler]['width'] = params[coupler].get(
393
+ 'width', coupler_size)
394
+ layout['couplers'][coupler]['fontsize'] = params[coupler].get(
395
+ 'fontsize', coupler_fontsize)
396
+ layout['couplers'][coupler]['text'] = params[coupler].get(
397
+ 'text', '')
398
+ layout['couplers'][coupler]['text_color'] = params[coupler].get(
399
+ 'text_color', 'k')
400
+ else:
401
+ layout['couplers'][coupler]['color'] = coupler_color
402
+ if coupler_color is None:
403
+ layout['couplers'][coupler]['lw'] = lw
404
+ else:
405
+ layout['couplers'][coupler]['lw'] = 0
406
+ layout['couplers'][coupler]['bounder_color'] = bounder_color
407
+
408
+ return layout
@@ -0,0 +1,242 @@
1
+ import itertools
2
+
3
+ import matplotlib.pyplot as plt
4
+ import numpy as np
5
+ from matplotlib.patches import PathPatch
6
+ from matplotlib.path import Path
7
+
8
+
9
+ def cycle(x0, y0, r, a=0, b=2 * np.pi):
10
+ t = np.linspace(a, b, 101)
11
+ x = r * np.cos(t) + x0
12
+ y = r * np.sin(t) + y0
13
+ return x, y
14
+
15
+
16
+ def plotSquare(xc, yc, xs, ys, radius=0, color='C0', ax=None):
17
+ ax = plt.gca() if ax is None else ax
18
+
19
+ l, r, b, u = xc - xs / 2, xc + xs / 2, yc - ys / 2, yc + ys / 2
20
+ x = np.linspace(l + radius, r - radius, 2)
21
+ y = np.linspace(b + radius, u - radius, 2)
22
+
23
+ ax.plot(x, [u, u], color=color)
24
+ ax.plot(x, [b, b], color=color)
25
+ ax.plot([l, l], y, color=color)
26
+ ax.plot([r, r], y, color=color)
27
+
28
+ xx, yy = cycle(x[-1], y[-1], radius, 0, np.pi / 2)
29
+ ax.plot(xx, yy, color=color)
30
+
31
+ xx, yy = cycle(x[0], y[-1], radius, np.pi / 2, np.pi)
32
+ ax.plot(xx, yy, color=color)
33
+
34
+ xx, yy = cycle(x[0], y[0], radius, np.pi, np.pi * 3 / 2)
35
+ ax.plot(xx, yy, color=color)
36
+
37
+ xx, yy = cycle(x[-1], y[0], radius, np.pi * 3 / 2, np.pi * 2)
38
+ ax.plot(xx, yy, color=color)
39
+
40
+
41
+ def plotMesure(x0=0, y0=0, size=1, color='C0', ax=None):
42
+
43
+ ax = plt.gca() if ax is None else ax
44
+
45
+ x, y = cycle(x0, y0 - 0.37 * size, 0.57 * size, np.pi / 4, np.pi * 3 / 4)
46
+ ax.plot(x, y, color=color)
47
+
48
+ plotSquare(x0, y0, size, 0.8 * size, radius=0.2 * size, color=color, ax=ax)
49
+
50
+ angle = np.pi / 6
51
+
52
+ ax.arrow(x0,
53
+ y0 - 0.25 * size,
54
+ 0.55 * size * np.sin(angle),
55
+ 0.55 * size * np.cos(angle),
56
+ head_width=0.07 * size,
57
+ head_length=0.1 * size,
58
+ color=color)
59
+
60
+
61
+ def plot_seq(ax, waves, measure=[1], gap=4, maxTime=20, xlim=None):
62
+ t = np.linspace(0, maxTime, 1001)
63
+ tt = np.linspace(0, maxTime - gap, 1001)
64
+ styles = ['-', '--', ':', '-.']
65
+ colors = ['C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9']
66
+ for i, (wavgroup, color) in enumerate(zip(waves, itertools.cycle(colors))):
67
+ if i in measure:
68
+ time = tt
69
+ else:
70
+ time = t
71
+ if not isinstance(wavgroup, tuple):
72
+ wavgroup = (wavgroup, )
73
+
74
+ for wav, style in zip(wavgroup, itertools.cycle(styles)):
75
+ ax.plot(time, wav(time) - gap * i, style, color=color)
76
+ if i in measure:
77
+ plotMesure(maxTime - gap / 2,
78
+ -gap * i,
79
+ gap,
80
+ color='black',
81
+ ax=ax)
82
+
83
+ ax.axis('equal')
84
+
85
+ ax.spines['left'].set_visible(False)
86
+ ax.spines['right'].set_visible(False)
87
+ ax.spines['bottom'].set_visible(False)
88
+ ax.spines['top'].set_visible(False)
89
+ ax.set_xticks([])
90
+ ax.set_yticks([])
91
+ if xlim is not None:
92
+ ax.set_xlim(xlim)
93
+
94
+
95
+ def make_path(fx, fy, dfx, dfy, t):
96
+
97
+ def p(fx, fy, dfx, dfy, t0, t1):
98
+ x1, x2 = fx(t0), fx(t1)
99
+ y1, y2 = fy(t0), fy(t1)
100
+ dx1, dx2 = dfx(t0), dfx(t1)
101
+ dy1, dy2 = dfy(t0), dfy(t1)
102
+
103
+ xp = (dy1 * dx2 * x1 - dy2 * dx1 * x2 - dx1 * dx2 *
104
+ (y1 - y2)) / (dy1 * dx2 - dy2 * dx1)
105
+
106
+ yp = (dy1 * dx2 * y2 - dy2 * dx1 * y1 + dy1 * dy2 *
107
+ (x1 - x2)) / (dy1 * dx2 - dy2 * dx1)
108
+
109
+ return xp, yp
110
+
111
+ path = [(fx(t[0]), fy(t[0]))]
112
+ codes = [Path.MOVETO]
113
+
114
+ for i in range(1, len(t)):
115
+ x, y = p(fx, fy, dfx, dfy, t[i - 1], t[i])
116
+ path.append((x, y))
117
+ codes.append(Path.CURVE3)
118
+ path.append((fx(t[i]), fy(t[i])))
119
+ codes.append(Path.CURVE3)
120
+ return path, codes
121
+
122
+
123
+ def plot_square(ax,
124
+ x=0,
125
+ y=0,
126
+ width=1,
127
+ hight=1,
128
+ r=0.2,
129
+ ls='-',
130
+ lw=2,
131
+ fc='none',
132
+ ec='black'):
133
+
134
+ path = np.array([(0, 1), (1 - 2 * r, 1), (1, 1), (1, 1 - 2 * r),
135
+ (1, -1 + 2 * r), (1, -1), (1 - 2 * r, -1),
136
+ (-1 + 2 * r, -1), (-1, -1), (-1, -1 + 2 * r),
137
+ (-1, 1 - 2 * r), (-1, 1), (-1 + 2 * r, 1), (0, 1)])
138
+ path[:, 0] = path[:, 0] * width / 2 + x
139
+ path[:, 1] = path[:, 1] * hight / 2 + y
140
+ codes = [
141
+ Path.MOVETO,
142
+ Path.LINETO,
143
+ Path.CURVE3,
144
+ Path.CURVE3,
145
+ Path.LINETO,
146
+ Path.CURVE3,
147
+ Path.CURVE3,
148
+ Path.LINETO,
149
+ Path.CURVE3,
150
+ Path.CURVE3,
151
+ Path.LINETO,
152
+ Path.CURVE3,
153
+ Path.CURVE3,
154
+ Path.CLOSEPOLY,
155
+ ]
156
+ pp1 = PathPatch(Path(path, codes),
157
+ ls=ls,
158
+ lw=lw,
159
+ fc=fc,
160
+ ec=ec,
161
+ transform=ax.transData)
162
+
163
+ ax.add_patch(pp1)
164
+
165
+
166
+ def plot_measure(ax,
167
+ x=0,
168
+ y=0,
169
+ size=1,
170
+ r=0.2,
171
+ ls='-',
172
+ lw=2,
173
+ fc='none',
174
+ ec='black'):
175
+ width = size
176
+ hight = 0.8 * size
177
+ plot_square(ax, x, y, width, hight, r, ls, lw, fc, ec)
178
+
179
+ fx = lambda t: 0.5 * width * np.cos(t) + x
180
+ fy = lambda t: 0.5 * hight * np.sin(t) + y - 0.2 * hight
181
+ dfx = lambda t: -0.5 * width * np.sin(t)
182
+ dfy = lambda t: 0.5 * hight * np.cos(t)
183
+ t = np.linspace(1 / 6, 5 / 6, 5) * np.pi
184
+ path, codes = make_path(fx, fy, dfx, dfy, t)
185
+
186
+ pp1 = PathPatch(Path(path, codes),
187
+ ls=ls,
188
+ lw=lw,
189
+ fc=fc,
190
+ ec=ec,
191
+ transform=ax.transData)
192
+
193
+ ax.add_patch(pp1)
194
+
195
+ angle = np.pi / 6
196
+
197
+ ax.arrow(x,
198
+ y - 0.25 * width,
199
+ 0.55 * width * np.sin(angle),
200
+ 0.55 * width * np.cos(angle),
201
+ head_width=0.07 * width,
202
+ head_length=0.1 * width,
203
+ lw=lw,
204
+ color=ec)
205
+
206
+ return (x - width / 2, x + width / 2)
207
+
208
+
209
+ def plot_gate(ax,
210
+ x=0,
211
+ y=0,
212
+ size=1,
213
+ text="$U$",
214
+ ls='-',
215
+ lw=2,
216
+ r=0.2,
217
+ fc='none',
218
+ ec='black',
219
+ fontsize=16):
220
+ width = size
221
+ hight = 0.8 * size
222
+ plot_square(ax, x, y, width, hight, r, ls, lw, fc, ec)
223
+ ax.text(x, y, text, ha='center', va='center', color=ec, fontsize=fontsize)
224
+
225
+ return (x - width / 2, x + width / 2)
226
+
227
+
228
+ def plot_waveform(ax,
229
+ wav,
230
+ offset,
231
+ gaps=[],
232
+ ec='black',
233
+ fc='none',
234
+ ls='-',
235
+ lw=2):
236
+ t = np.linspace(wav.start, wav.stop, 1001)
237
+ points = wav(t) + offset
238
+ for a, b in gaps:
239
+ points[(t > a) * (t < b)] = np.nan
240
+ ax.plot(t, points, ls=ls, color=ec, lw=lw)
241
+ if fc != 'none':
242
+ ax.fill_between(t, points, offset, color=fc)