QuLab 2.4.0__cp312-cp312-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 (97) hide show
  1. QuLab-2.4.0.dist-info/LICENSE +21 -0
  2. QuLab-2.4.0.dist-info/METADATA +105 -0
  3. QuLab-2.4.0.dist-info/RECORD +97 -0
  4. QuLab-2.4.0.dist-info/WHEEL +5 -0
  5. QuLab-2.4.0.dist-info/entry_points.txt +2 -0
  6. QuLab-2.4.0.dist-info/top_level.txt +1 -0
  7. qulab/__init__.py +3 -0
  8. qulab/__main__.py +30 -0
  9. qulab/dicttree.py +511 -0
  10. qulab/executor/__init__.py +5 -0
  11. qulab/executor/__main__.py +89 -0
  12. qulab/executor/load.py +202 -0
  13. qulab/executor/schedule.py +223 -0
  14. qulab/executor/storage.py +143 -0
  15. qulab/executor/transform.py +90 -0
  16. qulab/executor/utils.py +107 -0
  17. qulab/fun.cpython-312-darwin.so +0 -0
  18. qulab/monitor/__init__.py +1 -0
  19. qulab/monitor/__main__.py +8 -0
  20. qulab/monitor/config.py +41 -0
  21. qulab/monitor/dataset.py +77 -0
  22. qulab/monitor/event_queue.py +54 -0
  23. qulab/monitor/mainwindow.py +234 -0
  24. qulab/monitor/monitor.py +93 -0
  25. qulab/monitor/ploter.py +123 -0
  26. qulab/monitor/qt_compat.py +16 -0
  27. qulab/monitor/toolbar.py +265 -0
  28. qulab/scan/__init__.py +3 -0
  29. qulab/scan/curd.py +221 -0
  30. qulab/scan/expression.py +646 -0
  31. qulab/scan/models.py +554 -0
  32. qulab/scan/optimize.py +76 -0
  33. qulab/scan/query.py +374 -0
  34. qulab/scan/record.py +603 -0
  35. qulab/scan/scan.py +1166 -0
  36. qulab/scan/server.py +533 -0
  37. qulab/scan/space.py +213 -0
  38. qulab/scan/utils.py +229 -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 +0 -0
  58. qulab/sys/chat.py +688 -0
  59. qulab/sys/device/__init__.py +3 -0
  60. qulab/sys/device/basedevice.py +229 -0
  61. qulab/sys/device/loader.py +86 -0
  62. qulab/sys/device/utils.py +79 -0
  63. qulab/sys/drivers/FakeInstrument.py +52 -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 +192 -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 +220 -0
  88. qulab/version.py +1 -0
  89. qulab/visualization/__init__.py +188 -0
  90. qulab/visualization/__main__.py +71 -0
  91. qulab/visualization/_autoplot.py +464 -0
  92. qulab/visualization/plot_circ.py +319 -0
  93. qulab/visualization/plot_layout.py +408 -0
  94. qulab/visualization/plot_seq.py +242 -0
  95. qulab/visualization/qdat.py +152 -0
  96. qulab/visualization/rot3d.py +23 -0
  97. qulab/visualization/widgets.py +86 -0
@@ -0,0 +1,646 @@
1
+ from __future__ import annotations
2
+
3
+ import operator
4
+
5
+ import numpy as np
6
+ from pyparsing import (CaselessKeyword, Combine, Forward, Group, Keyword,
7
+ Literal, Optional, ParserElement, Suppress, Word,
8
+ alphanums, alphas, delimitedList, nums, oneOf, opAssoc,
9
+ pyparsing_common, restOfLine, srange, stringEnd,
10
+ stringStart)
11
+ from scipy import special
12
+
13
+ LPAREN, RPAREN, LBRACK, RBRACK, LBRACE, RBRACE, DOT, TILDE, BANG, PLUS, MINUS = map(
14
+ Suppress, "()[]{}.~!+-")
15
+
16
+ INT = Combine(srange("[1-9]") +
17
+ Optional(Word(nums))).set_parse_action(lambda t: int(t[0]))
18
+ OCT = Combine("0" + Word("01234567")).set_parse_action(lambda t: int(t[0], 8))
19
+ HEX = Combine("0x" + Word("0123456789abcdefABCDEF")).set_parse_action(
20
+ lambda t: int(t[0], 16))
21
+ FLOAT = Combine(Word(nums) + DOT + Word(nums)) | \
22
+ Combine(DOT + Word(nums)) | \
23
+ Combine(Word(nums) + DOT) | \
24
+ Combine(Word(nums) + DOT + Word(nums) + CaselessKeyword("e") + Word("+-") + Word(nums)) | \
25
+ Combine(Word(nums) + DOT + CaselessKeyword("e") + Word("+-") + Word(nums)) | \
26
+ Combine(DOT + Word(nums) + CaselessKeyword("e") + Word("+-") + Word(nums)) | \
27
+ Combine(Word(nums) + CaselessKeyword("e") + Word("+-") + Word(nums))
28
+ FLOAT.set_parse_action(lambda t: float(t[0]))
29
+ SYMBOL = Word(alphas, alphanums + "_")
30
+ SYMBOL.set_parse_action(lambda t: Symbol(t[0]))
31
+
32
+ expr = Forward()
33
+ unary = Forward()
34
+ binary = Forward()
35
+ atom = Forward()
36
+
37
+ atom << (INT | OCT | HEX | FLOAT | SYMBOL | (LPAREN + expr + RPAREN) |
38
+ (LBRACK + expr + RBRACK) | (LBRACE + expr + RBRACE) | (MINUS + atom) |
39
+ (PLUS + atom) | (TILDE + atom) | (BANG + atom) | (nums + DOT + nums))
40
+
41
+ unary << (atom | (MINUS + unary) | (PLUS + unary) | (TILDE + unary) |
42
+ (BANG + unary))
43
+
44
+ ConstType = (int, float, complex)
45
+ _empty = object()
46
+
47
+
48
+ class Ref():
49
+ __slots__ = ['name']
50
+
51
+ def __init__(self, name):
52
+ self.name = name
53
+
54
+ def __repr__(self) -> str:
55
+ return f"Ref({self.name!r})"
56
+
57
+
58
+ class Env():
59
+
60
+ def __init__(self):
61
+ self.consts = {}
62
+ self.variables = {}
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
+ }
92
+
93
+ def __contains__(self, key):
94
+ return key in self.consts or key in self.variables or key in self.functions or key in self.refs
95
+
96
+ def __getitem__(self, key):
97
+ if key in self.consts:
98
+ return self.consts[key]
99
+ if key in self.variables:
100
+ return self.variables[key]
101
+ if key in self.functions:
102
+ return self.functions[key]
103
+ if key in self.refs:
104
+ return self[self.refs[key]]
105
+ raise KeyError(f"Key {key} not found")
106
+
107
+ def __setitem__(self, key, value):
108
+ if key in self.consts:
109
+ raise KeyError(f"Key {key:r} is const")
110
+ elif isinstance(value, Ref):
111
+ self.create_ref(key, value.name)
112
+ elif key in self.refs:
113
+ self[self.refs[key]] = value
114
+ else:
115
+ self.variables[key] = value
116
+
117
+ def __delitem__(self, key):
118
+ if key in self.consts:
119
+ raise KeyError(f"Key {key:r} is const")
120
+ elif key in self.refs:
121
+ del self[self.refs[key]]
122
+ else:
123
+ del self.variables[key]
124
+
125
+ def ref(self, key):
126
+ if key in self:
127
+ return Ref(key)
128
+ else:
129
+ raise KeyError(f"Key {key!r} not found")
130
+
131
+ def create_ref(self, key, name):
132
+ if name in self.refs:
133
+ if key in self.refs[name]:
134
+ raise ValueError(f"Key {key!r} already exists in ref {name!r}")
135
+ else:
136
+ self.refs[key] = [name, *self.refs[name]]
137
+ else:
138
+ self.refs[key] = [name]
139
+
140
+ def is_const(self, key):
141
+ return key in self.consts
142
+
143
+
144
+ _default_env = Env()
145
+
146
+
147
+ class Expression():
148
+
149
+ def __init__(self):
150
+ self.cache = _empty
151
+
152
+ def d(self, x: str | Symbol):
153
+ if isinstance(x, Symbol):
154
+ x = x.name
155
+ if x in self.symbols():
156
+ return self.derivative(x)
157
+ else:
158
+ return 0
159
+
160
+ def derivative(self, x):
161
+ raise NotImplementedError
162
+
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
168
+ return BinaryExpression(self, other, operator.add)
169
+
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
175
+ return BinaryExpression(other, self, operator.add)
176
+
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
182
+ return BinaryExpression(self, other, operator.sub)
183
+
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
189
+ return BinaryExpression(other, self, operator.sub)
190
+
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
200
+ return BinaryExpression(self, other, operator.mul)
201
+
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
211
+ return BinaryExpression(other, self, operator.mul)
212
+
213
+ def __matmul__(self, other):
214
+ if isinstance(other, Expression):
215
+ other = other.eval(_default_env)
216
+ return BinaryExpression(self, other, operator.matmul)
217
+
218
+ def __rmatmul__(self, other):
219
+ if isinstance(other, Expression):
220
+ other = other.eval(_default_env)
221
+ return BinaryExpression(other, self, operator.matmul)
222
+
223
+ def __truediv__(self, other):
224
+ if isinstance(other, Expression):
225
+ other = other.eval(_default_env)
226
+ if isinstance(other, ConstType) and other == 1:
227
+ return self
228
+ if isinstance(other, ConstType) and other == -1:
229
+ return -self
230
+ return BinaryExpression(self, other, operator.truediv)
231
+
232
+ def __rtruediv__(self, other):
233
+ if isinstance(other, Expression):
234
+ other = other.eval(_default_env)
235
+ if isinstance(other, ConstType) and other == 0:
236
+ return 0
237
+ return BinaryExpression(other, self, operator.truediv)
238
+
239
+ def __floordiv__(self, other):
240
+ if isinstance(other, Expression):
241
+ other = other.eval(_default_env)
242
+ if isinstance(other, ConstType) and other == 1:
243
+ return self
244
+ if isinstance(other, ConstType) and other == -1:
245
+ return -self
246
+ return BinaryExpression(self, other, operator.floordiv)
247
+
248
+ def __rfloordiv__(self, other):
249
+ if isinstance(other, Expression):
250
+ other = other.eval(_default_env)
251
+ if isinstance(other, ConstType) and other == 0:
252
+ return 0
253
+ return BinaryExpression(other, self, operator.floordiv)
254
+
255
+ def __mod__(self, other):
256
+ if isinstance(other, Expression):
257
+ other = other.eval(_default_env)
258
+ if isinstance(other, ConstType) and other == 1:
259
+ return 0
260
+ return BinaryExpression(self, other, operator.mod)
261
+
262
+ def __rmod__(self, other):
263
+ if isinstance(other, Expression):
264
+ other = other.eval(_default_env)
265
+ return BinaryExpression(other, self, operator.mod)
266
+
267
+ def __pow__(self, other):
268
+ if isinstance(other, Expression):
269
+ other = other.eval(_default_env)
270
+ if isinstance(other, ConstType) and other == 0:
271
+ return 1
272
+ if isinstance(other, ConstType) and other == 1:
273
+ return self
274
+ return BinaryExpression(self, other, operator.pow)
275
+
276
+ def __rpow__(self, other):
277
+ if isinstance(other, Expression):
278
+ other = other.eval(_default_env)
279
+ if isinstance(other, ConstType) and other == 0:
280
+ return 0
281
+ return BinaryExpression(other, self, operator.pow)
282
+
283
+ def __neg__(self):
284
+ return UnaryExpression(self, operator.neg)
285
+
286
+ def __pos__(self):
287
+ return UnaryExpression(self, operator.pos)
288
+
289
+ def __abs__(self):
290
+ return UnaryExpression(self, operator.abs)
291
+
292
+ def __not__(self):
293
+ return UnaryExpression(self, operator.not_)
294
+
295
+ def __inv__(self):
296
+ return UnaryExpression(self, operator.inv)
297
+
298
+ def __invert__(self):
299
+ return UnaryExpression(self, operator.invert)
300
+
301
+ def __index__(self):
302
+ return UnaryExpression(self, operator.index)
303
+
304
+ def __eq__(self, other):
305
+ if isinstance(other, Expression):
306
+ other = other.eval(_default_env)
307
+ return BinaryExpression(self, other, operator.eq)
308
+
309
+ def __ne__(self, other):
310
+ if isinstance(other, Expression):
311
+ other = other.eval(_default_env)
312
+ return BinaryExpression(self, other, operator.ne)
313
+
314
+ def __lt__(self, other):
315
+ if isinstance(other, Expression):
316
+ other = other.eval(_default_env)
317
+ return BinaryExpression(self, other, operator.lt)
318
+
319
+ def __le__(self, other):
320
+ if isinstance(other, Expression):
321
+ other = other.eval(_default_env)
322
+ return BinaryExpression(self, other, operator.le)
323
+
324
+ def __gt__(self, other):
325
+ if isinstance(other, Expression):
326
+ other = other.eval(_default_env)
327
+ return BinaryExpression(self, other, operator.gt)
328
+
329
+ def __ge__(self, other):
330
+ if isinstance(other, Expression):
331
+ other = other.eval(_default_env)
332
+ return BinaryExpression(self, other, operator.ge)
333
+
334
+ def __and__(self, other):
335
+ if isinstance(other, Expression):
336
+ other = other.eval(_default_env)
337
+ return BinaryExpression(self, other, operator.and_)
338
+
339
+ def __rand__(self, other):
340
+ if isinstance(other, Expression):
341
+ other
342
+ return BinaryExpression(other, self, operator.and_)
343
+
344
+ def __or__(self, other):
345
+ if isinstance(other, Expression):
346
+ other = other.eval(_default_env)
347
+ return BinaryExpression(self, other, operator.or_)
348
+
349
+ def __ror__(self, other):
350
+ if isinstance(other, Expression):
351
+ other = other.eval(_default_env)
352
+ return BinaryExpression(other, self, operator.or_)
353
+
354
+ def __lshift__(self, other):
355
+ if isinstance(other, Expression):
356
+ other = other.eval(_default_env)
357
+ return BinaryExpression(self, other, operator.lshift)
358
+
359
+ def __rlshift__(self, other):
360
+ if isinstance(other, Expression):
361
+ other = other.eval(_default_env)
362
+ return BinaryExpression(other, self, operator.lshift)
363
+
364
+ def __rshift__(self, other):
365
+ if isinstance(other, Expression):
366
+ other = other.eval(_default_env)
367
+ return BinaryExpression(self, other, operator.rshift)
368
+
369
+ def __rrshift__(self, other):
370
+ if isinstance(other, Expression):
371
+ other = other.eval(_default_env)
372
+ return BinaryExpression(other, self, operator.rshift)
373
+
374
+ def __xor__(self, other):
375
+ if isinstance(other, Expression):
376
+ other = other.eval(_default_env)
377
+ return BinaryExpression(self, other, operator.xor)
378
+
379
+ def __rxor__(self, other):
380
+ if isinstance(other, Expression):
381
+ other = other.eval(_default_env)
382
+ return BinaryExpression(other, self, operator.xor)
383
+
384
+ def __getitem__(self, other):
385
+ if isinstance(other, Expression):
386
+ other = other.eval(_default_env)
387
+ return ObjectMethod(self, '__getitem__', other)
388
+
389
+ def __getattr__(self, other):
390
+ if isinstance(other, str):
391
+ if other.startswith('_') or other in self.__dict__:
392
+ return super().__getattr__(other)
393
+ if isinstance(other, Expression):
394
+ other = other.eval(_default_env)
395
+ return ObjectMethod(self, '__getattr__', other)
396
+
397
+ def __call__(self, *args):
398
+ args = [
399
+ o.eval(_default_env) if isinstance(o, Expression) else o
400
+ for o in args
401
+ ]
402
+ return ObjectMethod(self, '__call__', *args)
403
+
404
+ def __round__(self, n=None):
405
+ return self
406
+
407
+ def __bool__(self):
408
+ return True
409
+
410
+ def eval(self, env):
411
+ raise NotImplementedError
412
+
413
+ def symbols(self) -> list[str]:
414
+ raise NotImplementedError
415
+
416
+ def changed(self, env) -> bool:
417
+ return True
418
+
419
+ def is_const(self, env) -> bool:
420
+ return False
421
+
422
+ def value(self, env=_default_env):
423
+ if isinstance(env, dict):
424
+ e = Env()
425
+ e.variables = env
426
+ env = e
427
+ if self.changed(env):
428
+ self.cache = self.eval(env)
429
+ return self.cache
430
+
431
+
432
+ class UnaryExpression(Expression):
433
+
434
+ def __init__(self, a, op):
435
+ super().__init__()
436
+ self.a = a
437
+ self.op = op
438
+
439
+ def __getstate__(self) -> dict:
440
+ return {'a': self.a, 'op': self.op}
441
+
442
+ def __setstate__(self, state: dict):
443
+ self.a = state['a']
444
+ self.op = state['op']
445
+ self.cache = _empty
446
+
447
+ def symbols(self) -> list[str]:
448
+ if isinstance(self.a, Expression):
449
+ return self.a.symbols()
450
+ else:
451
+ return []
452
+
453
+ def changed(self, env) -> bool:
454
+ if isinstance(self.a, ConstType):
455
+ return False
456
+ return self.cache is _empty or isinstance(
457
+ self.a, Expression) and self.a.changed(env)
458
+
459
+ def is_const(self, env) -> bool:
460
+ return isinstance(self.a,
461
+ Expression) and self.a.is_const(env) or isinstance(
462
+ self.a, ConstType)
463
+
464
+ def eval(self, env):
465
+ a = self.a.value(env) if isinstance(self.a, Expression) else self.a
466
+ return self.op(a)
467
+
468
+ def derivative(self, x):
469
+ if isinstance(self.a, Expression):
470
+ return self.op(self.a.d(x))
471
+ else:
472
+ return 0
473
+
474
+ def __repr__(self) -> str:
475
+ return f"{self.op.__name__}({self.a!r})"
476
+
477
+
478
+ class BinaryExpression(Expression):
479
+
480
+ def __init__(self, a, b, op):
481
+ super().__init__()
482
+ self.a = a
483
+ self.b = b
484
+ self.op = op
485
+
486
+ def __getstate__(self) -> dict:
487
+ return {'a': self.a, 'b': self.b, 'op': self.op}
488
+
489
+ def __setstate__(self, state: dict):
490
+ self.a = state['a']
491
+ self.b = state['b']
492
+ self.op = state['op']
493
+ self.cache = _empty
494
+
495
+ def symbols(self) -> list[str]:
496
+ symbs = set()
497
+ if isinstance(self.a, Expression):
498
+ symbs.update(self.a.symbols())
499
+ if isinstance(self.b, Expression):
500
+ symbs.update(self.b.symbols())
501
+ return list(symbs)
502
+
503
+ def eval(self, env):
504
+ a = self.a.value(env) if isinstance(self.a, Expression) else self.a
505
+ b = self.b.value(env) if isinstance(self.b, Expression) else self.b
506
+ return self.op(a, b)
507
+
508
+ def derivative(self, x):
509
+ if isinstance(self.a, Expression):
510
+ da = self.a.d(x)
511
+ else:
512
+ da = 0
513
+ if isinstance(self.b, Expression):
514
+ db = self.b.d(x)
515
+ else:
516
+ db = 0
517
+
518
+ if self.op is operator.add:
519
+ return da + db
520
+ elif self.op is operator.sub:
521
+ return da - db
522
+ elif self.op is operator.mul:
523
+ return self.a * db + da * self.b
524
+ elif self.op is operator.truediv:
525
+ return (da * self.b - self.a * db) / self.b**2
526
+ elif self.op is operator.pow:
527
+ if isinstance(self.a, Expression) and isinstance(
528
+ self.b, Expression):
529
+ return self.a**self.b * (self.b * da / self.a +
530
+ ObjectMethod(np, 'log', self.a) * db)
531
+ elif isinstance(self.a, Expression):
532
+ return self.b * self.a**(self.b - 1) * da
533
+ elif isinstance(self.b, Expression):
534
+ return np.log(self.a) * db * self.a**self.b
535
+ else:
536
+ return 0
537
+ else:
538
+ return 0
539
+
540
+ def __repr__(self) -> str:
541
+ return f"({self.a!r} {self.op.__name__} {self.b!r})"
542
+
543
+
544
+ class ObjectMethod(Expression):
545
+
546
+ def __init__(self, obj, method: str, *args):
547
+ super().__init__()
548
+ self.obj = obj
549
+ self.method = method
550
+ self.args = args
551
+
552
+ def __getstate__(self) -> dict:
553
+ return {'obj': self.obj, 'method': self.method, 'args': self.args}
554
+
555
+ def __setstate__(self, state: dict):
556
+ self.obj = state['obj']
557
+ self.method = state['method']
558
+ self.args = state['args']
559
+ self.cache = _empty
560
+
561
+ def symbols(self) -> list[str]:
562
+ symbs = set()
563
+ if isinstance(self.obj, Expression):
564
+ symbs.update(self.obj.symbols())
565
+ for a in self.args:
566
+ if isinstance(a, Expression):
567
+ symbs.update(a.symbols())
568
+ return list(symbs)
569
+
570
+ def eval(self, env):
571
+ obj = self.obj.value(env) if isinstance(self.obj,
572
+ Expression) else self.obj
573
+ args = [
574
+ a.value(env) if isinstance(a, Expression) else a for a in self.args
575
+ ]
576
+ if isinstance(obj, Expression) or any(
577
+ isinstance(x, Expression) for x in args):
578
+ return ObjectMethod(obj, self.method, *args)
579
+ else:
580
+ return getattr(obj, self.method)(*args)
581
+
582
+ def __repr__(self):
583
+ if self.method == '__call__':
584
+ return f"{self.obj!r}({', '.join(map(repr, self.args))})"
585
+ else:
586
+ return f"{self.obj!r}.{self.method}({', '.join(map(repr, self.args))})"
587
+
588
+
589
+ class Symbol(Expression):
590
+
591
+ def __init__(self, name):
592
+ super().__init__()
593
+ self.name = name
594
+
595
+ def __getstate__(self) -> dict:
596
+ return {'name': self.name}
597
+
598
+ def __setstate__(self, state: dict):
599
+ self.name = state['name']
600
+ self.cache = _empty
601
+
602
+ def symbols(self) -> list[str]:
603
+ return [self.name]
604
+
605
+ def eval(self, env):
606
+ if self.name in env:
607
+ return env[self.name]
608
+ else:
609
+ return self
610
+
611
+ def derivative(self, x):
612
+ if x == self.name:
613
+ return 1
614
+ else:
615
+ return 0
616
+
617
+ def __repr__(self) -> str:
618
+ return self.name
619
+
620
+
621
+ sin = Symbol('sin')
622
+ cos = Symbol('cos')
623
+ tan = Symbol('tan')
624
+ pi = Symbol('pi')
625
+ e = Symbol('e')
626
+ log = Symbol('log')
627
+ log2 = Symbol('log2')
628
+ log10 = Symbol('log10')
629
+ exp = Symbol('exp')
630
+ sqrt = Symbol('sqrt')
631
+ abs = Symbol('abs')
632
+ sinh = Symbol('sinh')
633
+ cosh = Symbol('cosh')
634
+ tanh = Symbol('tanh')
635
+ arcsin = Symbol('arcsin')
636
+ arccos = Symbol('arccos')
637
+ arctan = Symbol('arctan')
638
+ arctan2 = Symbol('arctan2')
639
+ arcsinh = Symbol('arcsinh')
640
+ arccosh = Symbol('arccosh')
641
+ arctanh = Symbol('arctanh')
642
+ sinc = Symbol('sinc')
643
+ sign = Symbol('sign')
644
+ heaviside = Symbol('heaviside')
645
+ erf = Symbol('erf')
646
+ erfc = Symbol('erfc')