waveforms 2.2.2__tar.gz → 2.3.0__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 (32) hide show
  1. waveforms-2.3.0/MANIFEST.in +4 -0
  2. {waveforms-2.2.2 → waveforms-2.3.0}/PKG-INFO +1 -1
  3. {waveforms-2.2.2 → waveforms-2.3.0}/pyproject.toml +3 -0
  4. {waveforms-2.2.2 → waveforms-2.3.0}/tests/test_waveform.py +38 -0
  5. {waveforms-2.2.2 → waveforms-2.3.0}/tests/test_wavevstack.py +10 -0
  6. waveforms-2.3.0/waveforms/Waveform.g4 +68 -0
  7. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/_waveform.pyx +177 -81
  8. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/distortion.py +17 -4
  9. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/version.py +1 -1
  10. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/waveform.py +11 -6
  11. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms.egg-info/PKG-INFO +1 -1
  12. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms.egg-info/SOURCES.txt +1 -0
  13. waveforms-2.2.2/MANIFEST.in +0 -3
  14. {waveforms-2.2.2 → waveforms-2.3.0}/LICENSE +0 -0
  15. {waveforms-2.2.2 → waveforms-2.3.0}/README.md +0 -0
  16. {waveforms-2.2.2 → waveforms-2.3.0}/setup.cfg +0 -0
  17. {waveforms-2.2.2 → waveforms-2.3.0}/setup.py +0 -0
  18. {waveforms-2.2.2 → waveforms-2.3.0}/src/waveform.h +0 -0
  19. {waveforms-2.2.2 → waveforms-2.3.0}/tests/test_multi_drag.py +0 -0
  20. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/WaveformLexer.py +0 -0
  21. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/WaveformListener.py +0 -0
  22. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/WaveformParser.py +0 -0
  23. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/__init__.py +0 -0
  24. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/__main__.py +0 -0
  25. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/_waveform.pyi +0 -0
  26. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/multy_drag.py +0 -0
  27. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/utils.py +0 -0
  28. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms/waveform_parser.py +0 -0
  29. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms.egg-info/dependency_links.txt +0 -0
  30. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms.egg-info/entry_points.txt +0 -0
  31. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms.egg-info/requires.txt +0 -0
  32. {waveforms-2.2.2 → waveforms-2.3.0}/waveforms.egg-info/top_level.txt +0 -0
@@ -0,0 +1,4 @@
1
+ include src/*.h
2
+ include waveforms/_waveform.pyx
3
+ include waveforms/Waveform.g4
4
+ include MANIFEST.in
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: waveforms
3
- Version: 2.2.2
3
+ Version: 2.3.0
4
4
  Summary: Edit waveforms used in experiment
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -68,5 +68,8 @@ content-type = "text/markdown"
68
68
  license-files = ["LICENSE"]
69
69
  include-package-data = true
70
70
 
71
+ [tool.setuptools.package-data]
72
+ waveforms = ["WaveformLexer.py", "WaveformParser.py", "WaveformListener.py"]
73
+
71
74
  [tool.setuptools.dynamic]
72
75
  version = {attr = "waveforms.version.__version__"}
@@ -138,6 +138,44 @@ def test_chirp():
138
138
  assert np.allclose(wav3(t), _chirp(t, 1, 2, 10, 4, 'hyperbolic'))
139
139
 
140
140
 
141
+ def test_gaussian_derivative_and_mollifier():
142
+ x = np.linspace(-1.999, 1.999, 4097)
143
+
144
+ width = 4.0
145
+ std_sq2 = width / 3.3302184446307908
146
+ n = 8
147
+ expected = ((-1)**n / std_sq2**n
148
+ * special.eval_hermite(n, x / std_sq2)
149
+ * np.exp(-(x / std_sq2)**2))
150
+ assert np.allclose(gaussian(width, d=n)(x), expected)
151
+
152
+ d = 6
153
+ r = width / 2
154
+ scaled = x / r
155
+ xx_1 = scaled * scaled - 1
156
+ p = np.poly1d([-2, 0])
157
+ for order in range(1, d):
158
+ p = (np.poly1d([1, 0, -2, 0, 1]) * p.deriv()
159
+ + np.poly1d([-4 * order, 0, 4 * order - 2, 0]) * p)
160
+ expected = (np.exp(1 / xx_1 + 1) / (-xx_1)**(2 * d)
161
+ * p(scaled) / r**d)
162
+ assert np.allclose(mollifier(width, d=d)(x), expected)
163
+
164
+
165
+ def test_sampling_points_and_clipping():
166
+ x = np.linspace(-2.0, 2.0, 4096, endpoint=False)
167
+ points = tuple(np.sin(np.linspace(0.0, 3.0, 65)))
168
+ wav = samplingPoints(-2.0, 2.0, points)
169
+ assert np.allclose(wav(x), np.interp(x, np.linspace(-2.0, 2.0, 65),
170
+ points))
171
+
172
+ wav = 2.0 * cos(2.1) + 0.3 * sin(0.7)
173
+ wav.min = -0.4
174
+ wav.max = 0.6
175
+ assert np.allclose(wav(x), np.clip(2.0 * np.cos(2.1 * x)
176
+ + 0.3 * np.sin(0.7 * x), -0.4, 0.6))
177
+
178
+
141
179
  def test_parser():
142
180
  assert wave_eval("one()") == one()
143
181
  assert wave_eval("zero()") == zero()
@@ -141,3 +141,13 @@ def test_wave_sum():
141
141
  assert wave_sum([((-1.0, np.inf), (((), ()), ((((), ()), ), (0.02, )))),
142
142
  ((-1.0, np.inf), (((), ()), ((((), ()), ), (-0.02, ))))
143
143
  ]) == ((np.inf, ), (((), ()), ))
144
+
145
+
146
+ def test_wave_sum_preserves_value_before_a_new_earliest_bound():
147
+ source = (square(1.0) >> 5.0, const(2.0), square(1.0))
148
+ waves = [(wav.bounds, wav.seq) for wav in source]
149
+ combined = Waveform(*wave_sum(waves))
150
+ x = np.array([-10.0, 0.0, 2.0, 5.0, 10.0])
151
+ expected = sum(wav(x) for wav in source)
152
+
153
+ assert np.allclose(combined(x), expected)
@@ -0,0 +1,68 @@
1
+ grammar Waveform;
2
+
3
+ // 主规则
4
+ expr: assignment | expression ;
5
+
6
+ assignment: ID '=' expression ;
7
+
8
+ expression
9
+ : expression op=('**' | '^') expression # PowerExpression
10
+ | expression op=('*' | '/') expression # MultiplyDivideExpression
11
+ | expression op=('+' | '-') expression # AddSubtractExpression
12
+ | expression op=('<<' | '>>') expression # ShiftExpression
13
+ | '(' expression ')' # ParenthesesExpression
14
+ | '-' expression # UnaryMinusExpression
15
+ | functionCall # FunctionCallExpression
16
+ | CONSTANT # ConstantExpression
17
+ | NUMBER # NumberExpression
18
+ | STRING # StringExpression
19
+ | list # ListExpression
20
+ | tuple # TupleExpression
21
+ | ID # IdentifierExpression
22
+ ;
23
+
24
+ functionCall
25
+ : ID '(' ')' # NoArgFunction
26
+ | ID '(' args ')' # ArgsFunction
27
+ | ID '(' kwargs ')' # KwargsFunction
28
+ | ID '(' args ',' kwargs ')' # ArgsKwargsFunction
29
+ ;
30
+
31
+ args: expression (',' expression)* ;
32
+
33
+ kwargs: kwarg (',' kwarg)* ;
34
+
35
+ kwarg: ID '=' expression ;
36
+
37
+ list: '[' ']' | '[' expression (',' expression)* ']' ;
38
+
39
+ tuple: '(' expression ',' ')' | '(' expression (',' expression)+ ')' ;
40
+
41
+ // 词法规则
42
+ NUMBER
43
+ : REAL
44
+ | INT
45
+ | IMAG
46
+ ;
47
+
48
+ REAL: (DIGIT+ ('.' DIGIT*)? | '.' DIGIT+) ([eE] [+-]? DIGIT+)? ;
49
+
50
+ INT: DIGIT+ ;
51
+
52
+ IMAG: (REAL | INT) 'j' ;
53
+
54
+ STRING: '"' (~["\r\n])* '"' | '\'' (~['\r\n])* '\'' ;
55
+
56
+ CONSTANT: 'pi' | 'e' | 'inf' ;
57
+
58
+ ID: [a-zA-Z_][a-zA-Z0-9_]* ;
59
+
60
+ // 运算符
61
+ POW: '**' ;
62
+ LSHIFT: '<<' ;
63
+ RSHIFT: '>>' ;
64
+
65
+ // 忽略空白字符
66
+ WS: [ \t\r\n]+ -> skip ;
67
+
68
+ fragment DIGIT: [0-9] ;
@@ -1,5 +1,6 @@
1
1
  import pickle
2
2
  from bisect import bisect_left
3
+ from functools import lru_cache
3
4
  from itertools import chain, product
4
5
 
5
6
  import numpy as np
@@ -127,90 +128,174 @@ def pow(x, n):
127
128
  return ret
128
129
 
129
130
 
130
- def _apply(function_lib, func_id, x, shift, *args):
131
- return function_lib[func_id](x - shift, *args)
131
+ cdef object _calc_impl(object wav, object x, object function_lib):
132
+ cdef dict value_cache = {}
133
+ cdef object term_list = wav[0]
134
+ cdef object coefficient_list = wav[1]
135
+ cdef object monomial
136
+ cdef object base_list
137
+ cdef object power_list
138
+ cdef object base
139
+ cdef object value
140
+ cdef object product_value
141
+ cdef object term_value
142
+ cdef object total = None
143
+ cdef object coefficient
144
+ cdef object func
145
+ cdef object shift
146
+ cdef object args
147
+ cdef Py_ssize_t i, j
148
+ cdef Py_ssize_t term_count = len(term_list)
149
+ cdef Py_ssize_t base_count
150
+
151
+ for i in range(term_count):
152
+ monomial = term_list[i]
153
+ base_list = monomial[0]
154
+ power_list = monomial[1]
155
+ coefficient = coefficient_list[i]
156
+ product_value = None
157
+ base_count = len(base_list)
158
+
159
+ for j in range(base_count):
160
+ base = base_list[j]
161
+ if base in value_cache:
162
+ value = value_cache[base]
163
+ else:
164
+ func = function_lib[base[0]]
165
+ shift = base[-1]
166
+ args = base[1:-1]
167
+ if shift == 0:
168
+ value = func(x, *args)
169
+ else:
170
+ value = func(x - shift, *args)
171
+ value_cache[base] = value
132
172
 
173
+ if power_list[j] != 1:
174
+ value = value**power_list[j]
133
175
 
134
- def _calc(wav, x, function_lib):
135
- lru_cache = {}
136
-
137
- def _calc_m(t, x):
138
- ret = 1
139
- for mt, n in zip(*t):
140
- if mt not in lru_cache:
141
- func_id, *args, shift = mt
142
- lru_cache[mt] = _apply(function_lib, func_id, x, shift, *args)
143
- if n == 1:
144
- ret = ret * lru_cache[mt]
176
+ if product_value is None:
177
+ product_value = value
145
178
  else:
146
- ret = ret * lru_cache[mt]**n
147
- return ret
179
+ product_value = product_value * value
180
+
181
+ if product_value is None:
182
+ term_value = coefficient
183
+ elif coefficient == 1:
184
+ term_value = product_value
185
+ else:
186
+ term_value = coefficient * product_value
187
+
188
+ if total is None:
189
+ total = term_value
190
+ else:
191
+ total = total + term_value
192
+
193
+ if total is None:
194
+ return 0
195
+ return total
148
196
 
149
- ret = 0
150
- for t, v in zip(*wav):
151
- ret = ret + v * _calc_m(t, x)
152
- return ret
197
+
198
+ def _calc(wav, x, function_lib):
199
+ return _calc_impl(wav, x, function_lib)
153
200
 
154
201
 
155
202
  def calc_parts(bounds, seq, x, function_lib, min=-inf, max=inf):
156
- range_list = np.searchsorted(x, bounds)
157
- parts = []
158
- start, stop = 0, 0
159
- dtype = float
160
- for i, stop in enumerate(range_list):
203
+ cdef object range_list = np.searchsorted(x, bounds)
204
+ cdef list parts = []
205
+ cdef object part
206
+ cdef object dtype = float
207
+ cdef Py_ssize_t i
208
+ cdef Py_ssize_t start = 0
209
+ cdef Py_ssize_t stop
210
+ cdef Py_ssize_t count = len(range_list)
211
+ cdef bint should_clip = min != -inf or max != inf
212
+
213
+ for i in range(count):
214
+ stop = range_list[i]
161
215
  if start < stop and seq[i] != _zero:
162
- part = np.clip(_calc(seq[i], x[start:stop], function_lib), min,
163
- max)
164
- if (isinstance(part, complex) or isinstance(part, np.ndarray)
165
- and isinstance(part[0], complex)):
216
+ part = _calc_impl(seq[i], x[start:stop], function_lib)
217
+ if should_clip:
218
+ part = np.clip(part, min, max)
219
+ if np.iscomplexobj(part):
166
220
  dtype = complex
167
221
  parts.append((start, stop, part))
168
222
  start = stop
169
223
  return parts, dtype
170
224
 
171
225
 
172
- def wave_sum(waves):
173
- if not waves:
174
- return ((+inf, ), (_zero, ))
175
-
176
- bounds, seq = waves[0]
177
- if not waves[1:]:
178
- return bounds, seq
179
- bounds, seq = list(bounds), list(seq)
180
-
181
- for bounds_, seq_ in waves[1:]:
182
- if len(bounds_) == 1:
183
- for i, s in enumerate(seq):
184
- seq[i] = add(s, seq_[0])
185
- elif len(bounds) == 1:
186
- bounds = list(bounds_)
187
- seq = [add(seq[0], s) for s in seq_]
188
- else:
189
- lo = 0
190
- for b, s in zip(bounds_, seq_):
191
- i = bisect_left(bounds, b, lo=lo)
192
- if bounds[i] > b:
193
- bounds.insert(i, b)
194
- if i == 0:
195
- seq.insert(i, s)
196
- else:
197
- seq.insert(i, add(s, seq[i]))
198
- up = i - 1
199
- else:
200
- up = i
201
- for j in range(lo + 1, up + 1):
202
- seq[j] = add(seq[j], s)
203
- lo = i
204
-
205
- i = 0
206
- while i < len(bounds) - 1:
207
- if seq[i] == seq[i + 1]:
208
- del seq[i]
209
- del bounds[i]
226
+ cdef void _accumulate_expr(dict accumulator, object expr, int sign):
227
+ cdef object term_list = expr[0]
228
+ cdef object value_list = expr[1]
229
+ cdef object term
230
+ cdef object value
231
+ cdef Py_ssize_t i
232
+ cdef Py_ssize_t count = len(term_list)
233
+
234
+ for i in range(count):
235
+ term = term_list[i]
236
+ value = accumulator.get(term, 0) + sign * value_list[i]
237
+ if value == 0:
238
+ accumulator.pop(term, None)
210
239
  else:
211
- i += 1
240
+ accumulator[term] = value
212
241
 
213
- return tuple(bounds), tuple(seq)
242
+
243
+ cdef object _snapshot_expr(dict accumulator):
244
+ cdef list items
245
+ if not accumulator:
246
+ return _zero
247
+ items = sorted(accumulator.items())
248
+ return (tuple(item[0] for item in items),
249
+ tuple(item[1] for item in items))
250
+
251
+
252
+ def wave_sum(waves):
253
+ cdef dict accumulator = {}
254
+ cdef dict events = {}
255
+ cdef list output_bounds = []
256
+ cdef list output_seq
257
+ cdef object bounds
258
+ cdef object seq
259
+ cdef object changes
260
+ cdef object old_expr
261
+ cdef object new_expr
262
+ cdef object expr
263
+ cdef object boundary
264
+ cdef Py_ssize_t i, j
265
+ cdef Py_ssize_t wave_count
266
+ cdef Py_ssize_t bound_count
267
+
268
+ if not waves:
269
+ return ((inf, ), (_zero, ))
270
+ if len(waves) == 1:
271
+ return waves[0]
272
+
273
+ wave_count = len(waves)
274
+ for i in range(wave_count):
275
+ bounds, seq = waves[i]
276
+ _accumulate_expr(accumulator, seq[0], 1)
277
+ bound_count = len(bounds)
278
+ for j in range(bound_count - 1):
279
+ boundary = bounds[j]
280
+ changes = events.get(boundary)
281
+ if changes is None:
282
+ changes = []
283
+ events[boundary] = changes
284
+ changes.append((seq[j], seq[j + 1]))
285
+
286
+ output_seq = [_snapshot_expr(accumulator)]
287
+ for boundary in sorted(events):
288
+ changes = events[boundary]
289
+ for old_expr, new_expr in changes:
290
+ _accumulate_expr(accumulator, old_expr, -1)
291
+ _accumulate_expr(accumulator, new_expr, 1)
292
+ expr = _snapshot_expr(accumulator)
293
+ if expr != output_seq[-1]:
294
+ output_bounds.append(boundary)
295
+ output_seq.append(expr)
296
+
297
+ output_bounds.append(inf)
298
+ return tuple(output_bounds), tuple(output_seq)
214
299
 
215
300
 
216
301
  def merge_waveform(b1, s1, b2, s2, oper):
@@ -296,8 +381,9 @@ def _GAUSSIAN(t, std_sq2):
296
381
 
297
382
 
298
383
  def _D_GAUSSIAN(t, std_sq2, n):
299
- return (-1)**n / std_sq2**n * special.hermite(n)(
300
- t / std_sq2) * np.exp(-(t / std_sq2)**2)
384
+ x = t / std_sq2
385
+ return ((-1)**n / std_sq2**n * special.eval_hermite(n, x)
386
+ * np.exp(-(x**2)))
301
387
 
302
388
 
303
389
  def _ERF(t, std_sq2):
@@ -316,8 +402,13 @@ def _EXP(t, alpha):
316
402
  return np.exp(alpha * t)
317
403
 
318
404
 
405
+ @lru_cache(maxsize=256)
406
+ def _interp_grid(start, stop, size):
407
+ return np.linspace(start, stop, size)
408
+
409
+
319
410
  def _INTERP(t, start, stop, points):
320
- return np.interp(t, np.linspace(start, stop, len(points)), points)
411
+ return np.interp(t, _interp_grid(start, stop, len(points)), points)
321
412
 
322
413
 
323
414
  def _LINEARCHIRP(t, f0, f1, T, phi0):
@@ -356,19 +447,24 @@ def _drag(t: np.ndarray, t0: float, freq: float, width: float, delta: float,
356
447
  return Omega_x * np.cos(wt) + Omega_y * np.sin(wt)
357
448
 
358
449
 
450
+ @lru_cache(maxsize=64)
451
+ def _mollifier_poly(d):
452
+ p = np.poly1d([-2, 0])
453
+ for n in range(1, d):
454
+ p = (np.poly1d([1, 0, -2, 0, 1]) * p.deriv()
455
+ + np.poly1d([-4 * n, 0, 4 * n - 2, 0]) * p)
456
+ return p
457
+
458
+
359
459
  def _mollifier(t: np.ndarray, r: float, d: int):
360
460
  x = t / r
361
- xx_1 = np.abs(x)**2 - 1
461
+ xx_1 = x * x - 1
362
462
  if d == 0:
363
- return np.where(xx_1 == 0, 0, np.exp(1 / xx_1 + 1))
364
- else:
365
- p = np.poly1d([-2, 0])
366
- for n in range(1, d):
367
- p = np.poly1d([1, 0, -2, 0, 1]) * p.deriv() + np.poly1d(
368
- [-4 * n, 0, 4 * n - 2, 0]) * p
369
- return np.where(xx_1 == 0, 0,
370
- np.exp(1 / xx_1 + 1) /
371
- (-xx_1)**(2 * d)) * p(x) / r**d
463
+ return np.where(xx_1 >= 0, 0, np.exp(1 / xx_1 + 1))
464
+ p = _mollifier_poly(d)
465
+ return (np.where(xx_1 >= 0, 0,
466
+ np.exp(1 / xx_1 + 1) / (-xx_1)**(2 * d))
467
+ * p(x) / r**d)
372
468
 
373
469
 
374
470
  LINEAR = registerBaseFunc(_LINEAR)
@@ -135,8 +135,18 @@ def exp_decay_filter(
135
135
  poles (p) and gain (k). See scipy.signal.lfilter for more.
136
136
 
137
137
  Returns:
138
- tuple: (b, a) array like, numerator (b) and denominator (a)
138
+ if output is 'ba', return (b, a) array like, numerator (b) and denominator (a)
139
139
  polynomials of the IIR filter. See scipy.signal.lfilter for more.
140
+ if output is 'sos', return array of second-order filter coefficients with shape
141
+ (n_sections, 6). See scipy.signal.sosfilt for more.
142
+ if output is 'zpk', return (z, p, k) array like, zeros (z), poles (p) and gain (k).
143
+ See scipy.signal.zpk2tf for more.
144
+
145
+ Raises:
146
+ ValueError: if output is not 'ba', 'sos', or 'zpk'
147
+
148
+ Notes:
149
+ The filter is stable if all poles are inside the unit circle.
140
150
  """
141
151
 
142
152
  if isinstance(amp, (int, float, complex)):
@@ -155,11 +165,14 @@ def exp_decay_filter(
155
165
  numerator = numerator + denominator
156
166
 
157
167
  z = cast(NDArray[np.float64], np.exp(-numerator.roots / sample_rate))
158
- p = cast(NDArray[np.float64], np.exp(-denominator.roots / sample_rate))
168
+ # p = cast(NDArray[np.float64], np.exp(-denominator.roots / sample_rate))
169
+ p = np.exp(-1 / (np.asarray(tau) * sample_rate))
170
+
159
171
  if inv:
160
172
  z, p = p, z
161
- k = cast(float,
162
- numerator(0) / denominator(0) * np.prod(1 - p) / np.prod(1 - z))
173
+ # remove poles outside the unit circle to make the filter stable
174
+ p = p[np.abs(p) < 1]
175
+ k = cast(float, (np.prod(1 - p) / np.prod(1 - z)).real)
163
176
 
164
177
  if output == 'sos':
165
178
  return cast(NDArray[np.float64], zpk2sos(z, p, k))
@@ -1,2 +1,2 @@
1
1
  """Define version number here and read it from setup.py automatically"""
2
- __version__ = "2.2.2"
2
+ __version__ = "2.3.0"
@@ -28,6 +28,14 @@ def _test_spec_num(num, spec):
28
28
  return False, x, 0
29
29
 
30
30
 
31
+ def _exp_num(s):
32
+ if "e" in s:
33
+ a, n = s.split("e")
34
+ n = float(n)
35
+ s = f"{a} \\times 10^{{{n:g}}}"
36
+ return s
37
+
38
+
31
39
  def _spec_num_latex(num):
32
40
  for spec, spec_latex in [(1, ''), (np.sqrt(2), '\\sqrt{2}'),
33
41
  (np.sqrt(3), '\\sqrt{3}'),
@@ -44,13 +52,14 @@ def _spec_num_latex(num):
44
52
  if x.numerator == 1:
45
53
  return f"{spec_latex}"
46
54
  else:
47
- return f"{x.numerator:g}{spec_latex}"
55
+ s = _exp_num(f"{x.numerator:g}")
56
+ return f"{s}{spec_latex}"
48
57
  else:
49
58
  if x.numerator < 0:
50
59
  return f"-\\frac{{{-x.numerator}}}{{{x.denominator}}}{spec_latex}"
51
60
  else:
52
61
  return f"\\frac{{{x.numerator}}}{{{x.denominator}}}{spec_latex}"
53
- return f"{num:g}"
62
+ return _exp_num(f"{num:g}")
54
63
 
55
64
 
56
65
  def _num_latex(num):
@@ -65,10 +74,6 @@ def _num_latex(num):
65
74
  s = _spec_num_latex(num.real)
66
75
  if s == '' and round(num.real) == 1:
67
76
  return '1'
68
- if "e" in s:
69
- a, n = s.split("e")
70
- n = float(n)
71
- s = f"{a} \\times 10^{{{n:g}}}"
72
77
  return s
73
78
 
74
79
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: waveforms
3
- Version: 2.2.2
3
+ Version: 2.3.0
4
4
  Summary: Edit waveforms used in experiment
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -7,6 +7,7 @@ src/waveform.h
7
7
  tests/test_multi_drag.py
8
8
  tests/test_waveform.py
9
9
  tests/test_wavevstack.py
10
+ waveforms/Waveform.g4
10
11
  waveforms/WaveformLexer.py
11
12
  waveforms/WaveformListener.py
12
13
  waveforms/WaveformParser.py
@@ -1,3 +0,0 @@
1
- include src/*.h
2
- include waveforms/_waveform.pyx
3
- include MANIFEST.in
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes