modelbase2 0.1.79__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. modelbase2/__init__.py +138 -26
  2. modelbase2/distributions.py +306 -0
  3. modelbase2/experimental/__init__.py +17 -0
  4. modelbase2/experimental/codegen.py +239 -0
  5. modelbase2/experimental/diff.py +227 -0
  6. modelbase2/experimental/notes.md +4 -0
  7. modelbase2/experimental/tex.py +521 -0
  8. modelbase2/fit.py +284 -0
  9. modelbase2/fns.py +185 -0
  10. modelbase2/integrators/__init__.py +19 -0
  11. modelbase2/integrators/int_assimulo.py +146 -0
  12. modelbase2/integrators/int_scipy.py +147 -0
  13. modelbase2/label_map.py +610 -0
  14. modelbase2/linear_label_map.py +301 -0
  15. modelbase2/mc.py +548 -0
  16. modelbase2/mca.py +280 -0
  17. modelbase2/model.py +1621 -0
  18. modelbase2/npe.py +343 -0
  19. modelbase2/parallel.py +171 -0
  20. modelbase2/parameterise.py +28 -0
  21. modelbase2/paths.py +36 -0
  22. modelbase2/plot.py +829 -0
  23. modelbase2/sbml/__init__.py +14 -0
  24. modelbase2/sbml/_data.py +77 -0
  25. modelbase2/sbml/_export.py +656 -0
  26. modelbase2/sbml/_import.py +585 -0
  27. modelbase2/sbml/_mathml.py +691 -0
  28. modelbase2/sbml/_name_conversion.py +52 -0
  29. modelbase2/sbml/_unit_conversion.py +74 -0
  30. modelbase2/scan.py +616 -0
  31. modelbase2/scope.py +96 -0
  32. modelbase2/simulator.py +635 -0
  33. modelbase2/surrogates/__init__.py +32 -0
  34. modelbase2/surrogates/_poly.py +66 -0
  35. modelbase2/surrogates/_torch.py +249 -0
  36. modelbase2/surrogates.py +316 -0
  37. modelbase2/types.py +352 -11
  38. modelbase2-0.2.0.dist-info/METADATA +81 -0
  39. modelbase2-0.2.0.dist-info/RECORD +42 -0
  40. {modelbase2-0.1.79.dist-info → modelbase2-0.2.0.dist-info}/WHEEL +1 -1
  41. modelbase2/core/__init__.py +0 -29
  42. modelbase2/core/algebraic_module_container.py +0 -130
  43. modelbase2/core/constant_container.py +0 -113
  44. modelbase2/core/data.py +0 -109
  45. modelbase2/core/name_container.py +0 -29
  46. modelbase2/core/reaction_container.py +0 -115
  47. modelbase2/core/utils.py +0 -28
  48. modelbase2/core/variable_container.py +0 -24
  49. modelbase2/ode/__init__.py +0 -13
  50. modelbase2/ode/integrator.py +0 -80
  51. modelbase2/ode/mca.py +0 -270
  52. modelbase2/ode/model.py +0 -470
  53. modelbase2/ode/simulator.py +0 -153
  54. modelbase2/utils/__init__.py +0 -0
  55. modelbase2/utils/plotting.py +0 -372
  56. modelbase2-0.1.79.dist-info/METADATA +0 -44
  57. modelbase2-0.1.79.dist-info/RECORD +0 -22
  58. {modelbase2-0.1.79.dist-info → modelbase2-0.2.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,691 @@
1
+ from __future__ import annotations
2
+
3
+ __all__ = [
4
+ "AST_TYPES",
5
+ "handle_ast_constant_e",
6
+ "handle_ast_constant_false",
7
+ "handle_ast_constant_pi",
8
+ "handle_ast_constant_true",
9
+ "handle_ast_divide",
10
+ "handle_ast_divide_int",
11
+ "handle_ast_function",
12
+ "handle_ast_function_abs",
13
+ "handle_ast_function_ceiling",
14
+ "handle_ast_function_delay",
15
+ "handle_ast_function_exp",
16
+ "handle_ast_function_factorial",
17
+ "handle_ast_function_floor",
18
+ "handle_ast_function_ln",
19
+ "handle_ast_function_log",
20
+ "handle_ast_function_max",
21
+ "handle_ast_function_min",
22
+ "handle_ast_function_piecewise",
23
+ "handle_ast_function_power",
24
+ "handle_ast_function_rate_of",
25
+ "handle_ast_function_rem",
26
+ "handle_ast_function_root",
27
+ "handle_ast_integer",
28
+ "handle_ast_lambda",
29
+ "handle_ast_logical_and",
30
+ "handle_ast_logical_implies",
31
+ "handle_ast_logical_not",
32
+ "handle_ast_logical_or",
33
+ "handle_ast_logical_xor",
34
+ "handle_ast_minus",
35
+ "handle_ast_name",
36
+ "handle_ast_name_avogadro",
37
+ "handle_ast_name_time",
38
+ "handle_ast_originates_in_package",
39
+ "handle_ast_plus",
40
+ "handle_ast_rational",
41
+ "handle_ast_real",
42
+ "handle_ast_relational_eq",
43
+ "handle_ast_relational_geq",
44
+ "handle_ast_relational_gt",
45
+ "handle_ast_relational_leq",
46
+ "handle_ast_relational_lt",
47
+ "handle_ast_relational_neq",
48
+ "handle_ast_times",
49
+ "handle_ast_trigonometric_arc_cos",
50
+ "handle_ast_trigonometric_arc_cosh",
51
+ "handle_ast_trigonometric_arc_cot",
52
+ "handle_ast_trigonometric_arc_coth",
53
+ "handle_ast_trigonometric_arc_csc",
54
+ "handle_ast_trigonometric_arc_csch",
55
+ "handle_ast_trigonometric_arc_sec",
56
+ "handle_ast_trigonometric_arc_sech",
57
+ "handle_ast_trigonometric_arc_sin",
58
+ "handle_ast_trigonometric_arc_sinh",
59
+ "handle_ast_trigonometric_arc_tan",
60
+ "handle_ast_trigonometric_arc_tanh",
61
+ "handle_ast_trigonometric_cos",
62
+ "handle_ast_trigonometric_cosh",
63
+ "handle_ast_trigonometric_cot",
64
+ "handle_ast_trigonometric_coth",
65
+ "handle_ast_trigonometric_csc",
66
+ "handle_ast_trigonometric_csch",
67
+ "handle_ast_trigonometric_sec",
68
+ "handle_ast_trigonometric_sech",
69
+ "handle_ast_trigonometric_sin",
70
+ "handle_ast_trigonometric_sinh",
71
+ "handle_ast_trigonometric_tan",
72
+ "handle_ast_trigonometric_tanh",
73
+ "parse_sbml_math",
74
+ ]
75
+
76
+ from typing import TYPE_CHECKING, Any
77
+
78
+ from ._name_conversion import _name_to_py
79
+ from ._unit_conversion import get_ast_types
80
+
81
+ if TYPE_CHECKING:
82
+ from libsbml import ASTNode
83
+
84
+ AST_TYPES = get_ast_types()
85
+
86
+
87
+ def handle_ast_constant_e(
88
+ node: ASTNode, # noqa: ARG001
89
+ func_arguments: list[str], # noqa: ARG001
90
+ ) -> str:
91
+ return "math.e"
92
+
93
+
94
+ def handle_ast_constant_false(
95
+ node: ASTNode, # noqa: ARG001
96
+ func_arguments: list[str], # noqa: ARG001
97
+ ) -> str:
98
+ return "False"
99
+
100
+
101
+ def handle_ast_constant_true(
102
+ node: ASTNode, # noqa: ARG001
103
+ func_arguments: list[str], # noqa: ARG001
104
+ ) -> str:
105
+ return "True"
106
+
107
+
108
+ def handle_ast_constant_pi(
109
+ node: ASTNode, # noqa: ARG001
110
+ func_arguments: list[str], # noqa: ARG001
111
+ ) -> str:
112
+ return "math.pi"
113
+
114
+
115
+ def handle_ast_divide(node: ASTNode, func_arguments: list[str]) -> str:
116
+ children = [
117
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
118
+ for i in range(node.getNumChildren())
119
+ ]
120
+ bracketed_children = []
121
+ for child in children:
122
+ if len(child.split("+")) > 1:
123
+ bracketed_children.append(f"({child})")
124
+ else:
125
+ bracketed_children.append(child)
126
+ return " / ".join(bracketed_children)
127
+
128
+
129
+ def handle_ast_divide_int(node: ASTNode, func_arguments: list[str]) -> str:
130
+ children = [
131
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
132
+ for i in range(node.getNumChildren())
133
+ ]
134
+ bracketed_children = []
135
+ for child in children:
136
+ if len(child.split("+")) > 1:
137
+ bracketed_children.append(f"({child})")
138
+ else:
139
+ bracketed_children.append(child)
140
+ return " // ".join(bracketed_children)
141
+
142
+
143
+ def handle_ast_function(node: ASTNode, func_arguments: list[str]) -> str:
144
+ children = [
145
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
146
+ for i in range(node.getNumChildren())
147
+ ]
148
+ node_name = node.getName()
149
+ arguments = ", ".join(children)
150
+ return f"{node_name}({arguments})"
151
+
152
+
153
+ def handle_ast_function_abs(node: ASTNode, func_arguments: list[str]) -> str:
154
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
155
+ return f"np.abs({child})"
156
+
157
+
158
+ def handle_ast_function_ceiling(node: ASTNode, func_arguments: list[str]) -> str:
159
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
160
+ return f"np.ceil({child})"
161
+
162
+
163
+ def handle_ast_function_delay(node: ASTNode, func_arguments: list[str]) -> str:
164
+ raise NotImplementedError
165
+
166
+
167
+ def handle_ast_function_exp(node: ASTNode, func_arguments: list[str]) -> str:
168
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
169
+ return f"np.exp({child})"
170
+
171
+
172
+ def handle_ast_function_factorial(node: ASTNode, func_arguments: list[str]) -> str:
173
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
174
+ return f"scipy.special.factorial({child})"
175
+
176
+
177
+ def handle_ast_function_floor(node: ASTNode, func_arguments: list[str]) -> str:
178
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
179
+ return f"np.floor({child})"
180
+
181
+
182
+ def handle_ast_function_ln(node: ASTNode, func_arguments: list[str]) -> str:
183
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
184
+ return f"np.log({child})"
185
+
186
+
187
+ def handle_ast_function_log(node: ASTNode, func_arguments: list[str]) -> str:
188
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
189
+ return f"np.log10({child})"
190
+
191
+
192
+ def handle_ast_function_max(node: ASTNode, func_arguments: list[str]) -> str:
193
+ children = [
194
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
195
+ for i in range(node.getNumChildren())
196
+ ]
197
+ args = ", ".join(children)
198
+ return f"np.max([{args}])"
199
+
200
+
201
+ def handle_ast_function_min(node: ASTNode, func_arguments: list[str]) -> str:
202
+ children = [
203
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
204
+ for i in range(node.getNumChildren())
205
+ ]
206
+ args = ", ".join(children)
207
+ return f"np.min({args})"
208
+
209
+
210
+ def handle_ast_function_piecewise(node: ASTNode, func_arguments: list[str]) -> str:
211
+ children = [
212
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
213
+ for i in range(node.getNumChildren())
214
+ ]
215
+ if len(children) == 3: # noqa: PLR2004
216
+ condition = children[1]
217
+ x = children[0]
218
+ y = children[2]
219
+ return f"np.where({condition}, {x}, {y})"
220
+ return f"({children[0]} if {children[1]} else 0.0)"
221
+
222
+
223
+ def handle_ast_function_power(node: ASTNode, func_arguments: list[str]) -> str:
224
+ children = [
225
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
226
+ for i in range(node.getNumChildren())
227
+ ]
228
+ left_subchildren = node.getChild(0).getChild(0) is not None
229
+ right_subchildren = node.getChild(1).getChild(0) is not None
230
+ if left_subchildren and right_subchildren:
231
+ return f"({children[0]}) ** ({children[1]})"
232
+ if left_subchildren:
233
+ return f"({children[0]}) ** {children[1]}"
234
+ return f"{children[0]} ** ({children[1]})"
235
+
236
+
237
+ def handle_ast_function_rate_of(node: ASTNode, func_arguments: list[str]) -> str:
238
+ raise NotImplementedError
239
+
240
+
241
+ def handle_ast_function_root(node: ASTNode, func_arguments: list[str]) -> str:
242
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
243
+ return f"np.sqrt({child})"
244
+
245
+
246
+ def handle_ast_function_rem(node: ASTNode, func_arguments: list[str]) -> str:
247
+ children = [
248
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
249
+ for i in range(node.getNumChildren())
250
+ ]
251
+ args = ", ".join(children)
252
+ return f"np.remainder({args})"
253
+
254
+
255
+ def handle_ast_integer(
256
+ node: ASTNode,
257
+ func_arguments: list[str], # noqa: ARG001
258
+ ) -> str:
259
+ return str(int(node.getValue()))
260
+
261
+
262
+ def handle_ast_lambda(node: ASTNode, func_arguments: list[str]) -> str:
263
+ num_b_vars = node.getNumBvars()
264
+ num_children = node.getNumChildren()
265
+ children = [
266
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
267
+ for i in range(num_b_vars, num_children)
268
+ ]
269
+ return ", ".join(children)
270
+
271
+
272
+ def handle_ast_logical_and(node: ASTNode, func_arguments: list[str]) -> str:
273
+ children = [
274
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
275
+ for i in range(node.getNumChildren())
276
+ ]
277
+ if len(children) == 0:
278
+ return "and"
279
+ if len(children) == 1:
280
+ return "and"
281
+ args = " and ".join(children)
282
+ return f"({args})"
283
+
284
+
285
+ def handle_ast_logical_implies(
286
+ node: ASTNode,
287
+ func_arguments: list[str],
288
+ ) -> str:
289
+ raise NotImplementedError
290
+
291
+
292
+ def handle_ast_logical_not(node: ASTNode, func_arguments: list[str]) -> str:
293
+ children = [
294
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
295
+ for i in range(node.getNumChildren())
296
+ ]
297
+ if len(children) == 0:
298
+ return "not"
299
+ if len(children) == 1:
300
+ return f"not({children[0]})"
301
+ args = " not ".join(children)
302
+ return f"({args})"
303
+
304
+
305
+ def handle_ast_logical_or(node: ASTNode, func_arguments: list[str]) -> str:
306
+ children = [
307
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
308
+ for i in range(node.getNumChildren())
309
+ ]
310
+ if len(children) == 0:
311
+ return "or"
312
+ if len(children) == 1:
313
+ return "or"
314
+ args = " or ".join(children)
315
+ return f"({args})"
316
+
317
+
318
+ def handle_ast_logical_xor(node: ASTNode, func_arguments: list[str]) -> str:
319
+ children = [
320
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
321
+ for i in range(node.getNumChildren())
322
+ ]
323
+ if len(children) == 0:
324
+ return "^"
325
+ if len(children) == 1:
326
+ return "^"
327
+ children = [f"({i})" for i in children]
328
+ args = " ^ ".join(children)
329
+ return f"({args})"
330
+
331
+
332
+ def handle_ast_minus(node: ASTNode, func_arguments: list[str]) -> str:
333
+ children = [
334
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
335
+ for i in range(node.getNumChildren())
336
+ ]
337
+ if node.getNumChildren() == 1:
338
+ child = node.getChild(0)
339
+ child_str = children[0]
340
+ if child.getChild(0) is not None:
341
+ return f"-({child_str})"
342
+ return f"-{child_str}"
343
+ return " - ".join(children)
344
+
345
+
346
+ def handle_ast_name(node: ASTNode, func_arguments: list[str]) -> str:
347
+ name: str = _name_to_py(node.getName())
348
+ func_arguments.append(name)
349
+ return name
350
+
351
+
352
+ def handle_ast_name_avogadro(
353
+ node: ASTNode, # noqa: ARG001
354
+ func_arguments: list[str], # noqa: ARG001
355
+ ) -> str:
356
+ return "6.02214179e+23"
357
+
358
+
359
+ def handle_ast_name_time(
360
+ node: ASTNode, # noqa: ARG001
361
+ func_arguments: list[str],
362
+ ) -> str:
363
+ func_arguments.append("time")
364
+ return "time"
365
+
366
+
367
+ def handle_ast_originates_in_package(node: ASTNode, func_arguments: list[str]) -> str:
368
+ raise NotImplementedError
369
+
370
+
371
+ def handle_ast_plus(node: ASTNode, func_arguments: list[str]) -> str:
372
+ children = [
373
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
374
+ for i in range(node.getNumChildren())
375
+ ]
376
+ return " + ".join(children)
377
+
378
+
379
+ def handle_ast_rational(
380
+ node: ASTNode,
381
+ func_arguments: list[str], # noqa: ARG001
382
+ ) -> str:
383
+ return str(node.getValue())
384
+
385
+
386
+ def handle_ast_real(
387
+ node: ASTNode,
388
+ func_arguments: list[str], # noqa: ARG001
389
+ ) -> str:
390
+ value = str(node.getValue())
391
+ if value == "inf":
392
+ return "np.inf"
393
+ if value == "nan":
394
+ return "np.nan"
395
+ return value
396
+
397
+
398
+ def handle_ast_relational_eq(node: ASTNode, func_arguments: list[str]) -> str:
399
+ children = [
400
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
401
+ for i in range(node.getNumChildren())
402
+ ]
403
+ if len(children) > 2: # noqa: PLR2004
404
+ raise NotImplementedError
405
+ return f"{children[0]} == {children[1]}"
406
+
407
+
408
+ def handle_ast_relational_geq(node: ASTNode, func_arguments: list[str]) -> str:
409
+ children = [
410
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
411
+ for i in range(node.getNumChildren())
412
+ ]
413
+ if len(children) > 2: # noqa: PLR2004
414
+ raise NotImplementedError
415
+ return f"{children[0]} >= {children[1]}"
416
+
417
+
418
+ def handle_ast_relational_gt(node: ASTNode, func_arguments: list[str]) -> str:
419
+ children = [
420
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
421
+ for i in range(node.getNumChildren())
422
+ ]
423
+ if len(children) > 2: # noqa: PLR2004
424
+ raise NotImplementedError
425
+ return f"{children[0]} > {children[1]}"
426
+
427
+
428
+ def handle_ast_relational_leq(node: ASTNode, func_arguments: list[str]) -> str:
429
+ children = [
430
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
431
+ for i in range(node.getNumChildren())
432
+ ]
433
+ if len(children) > 2: # noqa: PLR2004
434
+ raise NotImplementedError
435
+ return f"{children[0]} <= {children[1]}"
436
+
437
+
438
+ def handle_ast_relational_lt(node: ASTNode, func_arguments: list[str]) -> str:
439
+ children = [
440
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
441
+ for i in range(node.getNumChildren())
442
+ ]
443
+ if len(children) > 2: # noqa: PLR2004
444
+ raise NotImplementedError
445
+ return f"{children[0]} < {children[1]}"
446
+
447
+
448
+ def handle_ast_relational_neq(node: ASTNode, func_arguments: list[str]) -> str:
449
+ children = [
450
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
451
+ for i in range(node.getNumChildren())
452
+ ]
453
+ if len(children) > 2: # noqa: PLR2004
454
+ raise NotImplementedError
455
+ return f"{children[0]} != {children[1]}"
456
+
457
+
458
+ def handle_ast_times(node: ASTNode, func_arguments: list[str]) -> str:
459
+ children = [
460
+ _handle_ast_node(node=node.getChild(i), func_arguments=func_arguments)
461
+ for i in range(node.getNumChildren())
462
+ ]
463
+ bracketed_children = []
464
+ for child in children:
465
+ if len(child.split("+")) > 1:
466
+ bracketed_children.append(f"({child})")
467
+ else:
468
+ bracketed_children.append(child)
469
+ return " * ".join(bracketed_children)
470
+
471
+
472
+ ###############################################################################
473
+ # Base
474
+ ###############################################################################
475
+
476
+
477
+ def handle_ast_trigonometric_sin(node: ASTNode, func_arguments: list[str]) -> str:
478
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
479
+ return f"np.sin({child})"
480
+
481
+
482
+ def handle_ast_trigonometric_cos(node: ASTNode, func_arguments: list[str]) -> str:
483
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
484
+ return f"np.cos({child})"
485
+
486
+
487
+ def handle_ast_trigonometric_tan(node: ASTNode, func_arguments: list[str]) -> str:
488
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
489
+ return f"np.tan({child})"
490
+
491
+
492
+ def handle_ast_trigonometric_sec(node: ASTNode, func_arguments: list[str]) -> str:
493
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
494
+ return f"1 / np.cos({child})"
495
+
496
+
497
+ def handle_ast_trigonometric_csc(node: ASTNode, func_arguments: list[str]) -> str:
498
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
499
+ return f"1 / np.sin({child})"
500
+
501
+
502
+ def handle_ast_trigonometric_cot(node: ASTNode, func_arguments: list[str]) -> str:
503
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
504
+ return f"1 / np.tan({child})"
505
+
506
+
507
+ ###############################################################################
508
+ # Inverse
509
+ ###############################################################################
510
+
511
+
512
+ def handle_ast_trigonometric_arc_sin(node: ASTNode, func_arguments: list[str]) -> str:
513
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
514
+ return f"np.arcsin({child})"
515
+
516
+
517
+ def handle_ast_trigonometric_arc_cos(node: ASTNode, func_arguments: list[str]) -> str:
518
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
519
+ return f"np.arccos({child})"
520
+
521
+
522
+ def handle_ast_trigonometric_arc_tan(node: ASTNode, func_arguments: list[str]) -> str:
523
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
524
+ return f"np.arctan({child})"
525
+
526
+
527
+ def handle_ast_trigonometric_arc_cot(node: ASTNode, func_arguments: list[str]) -> str:
528
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
529
+ return f"np.arctan(1 / ({child}))"
530
+
531
+
532
+ def handle_ast_trigonometric_arc_sec(node: ASTNode, func_arguments: list[str]) -> str:
533
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
534
+ return f"np.arccos(1 / ({child}))"
535
+
536
+
537
+ def handle_ast_trigonometric_arc_csc(node: ASTNode, func_arguments: list[str]) -> str:
538
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
539
+ return f"np.arcsin(1 / ({child}))"
540
+
541
+
542
+ ###############################################################################
543
+ # Hyperbolic
544
+ ###############################################################################
545
+
546
+
547
+ def handle_ast_trigonometric_sinh(node: ASTNode, func_arguments: list[str]) -> str:
548
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
549
+ return f"np.sinh({child})"
550
+
551
+
552
+ def handle_ast_trigonometric_cosh(node: ASTNode, func_arguments: list[str]) -> str:
553
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
554
+ return f"np.cosh({child})"
555
+
556
+
557
+ def handle_ast_trigonometric_tanh(node: ASTNode, func_arguments: list[str]) -> str:
558
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
559
+ return f"np.tanh({child})"
560
+
561
+
562
+ def handle_ast_trigonometric_sech(node: ASTNode, func_arguments: list[str]) -> str:
563
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
564
+ return f"1 / np.cosh({child})"
565
+
566
+
567
+ def handle_ast_trigonometric_csch(node: ASTNode, func_arguments: list[str]) -> str:
568
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
569
+ return f"1 / np.sinh({child})"
570
+
571
+
572
+ def handle_ast_trigonometric_coth(node: ASTNode, func_arguments: list[str]) -> str:
573
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
574
+ return f"1 / np.tanh({child})"
575
+
576
+
577
+ ###############################################################################
578
+ # Hyperbolic - inverse
579
+ ###############################################################################
580
+
581
+
582
+ def handle_ast_trigonometric_arc_sinh(node: ASTNode, func_arguments: list[str]) -> str:
583
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
584
+ return f"np.arcsinh({child})"
585
+
586
+
587
+ def handle_ast_trigonometric_arc_cosh(node: ASTNode, func_arguments: list[str]) -> str:
588
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
589
+ return f"np.arccosh({child})"
590
+
591
+
592
+ def handle_ast_trigonometric_arc_tanh(node: ASTNode, func_arguments: list[str]) -> str:
593
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
594
+ return f"np.arctanh({child})"
595
+
596
+
597
+ def handle_ast_trigonometric_arc_csch(node: ASTNode, func_arguments: list[str]) -> str:
598
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
599
+ return f"np.arcsinh(1 / {child})"
600
+
601
+
602
+ def handle_ast_trigonometric_arc_sech(node: ASTNode, func_arguments: list[str]) -> str:
603
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
604
+ return f"np.arccosh(1 / {child})"
605
+
606
+
607
+ def handle_ast_trigonometric_arc_coth(node: ASTNode, func_arguments: list[str]) -> str:
608
+ child = _handle_ast_node(node=node.getChild(0), func_arguments=func_arguments)
609
+ return f"np.arctanh(1 / {child})"
610
+
611
+
612
+ def _handle_ast_node(node: ASTNode, func_arguments: list[str]) -> str:
613
+ commands = {
614
+ "AST_CONSTANT_E": handle_ast_constant_e,
615
+ "AST_CONSTANT_FALSE": handle_ast_constant_false,
616
+ "AST_CONSTANT_PI": handle_ast_constant_pi,
617
+ "AST_CONSTANT_TRUE": handle_ast_constant_true,
618
+ "AST_DIVIDE": handle_ast_divide,
619
+ "AST_FUNCTION": handle_ast_function,
620
+ "AST_FUNCTION_ABS": handle_ast_function_abs,
621
+ "AST_FUNCTION_ARCCOS": handle_ast_trigonometric_arc_cos,
622
+ "AST_FUNCTION_ARCCOSH": handle_ast_trigonometric_arc_cosh,
623
+ "AST_FUNCTION_ARCCOT": handle_ast_trigonometric_arc_cot,
624
+ "AST_FUNCTION_ARCCOTH": handle_ast_trigonometric_arc_coth,
625
+ "AST_FUNCTION_ARCCSC": handle_ast_trigonometric_arc_csc,
626
+ "AST_FUNCTION_ARCCSCH": handle_ast_trigonometric_arc_csch,
627
+ "AST_FUNCTION_ARCSEC": handle_ast_trigonometric_arc_sec,
628
+ "AST_FUNCTION_ARCSECH": handle_ast_trigonometric_arc_sech,
629
+ "AST_FUNCTION_ARCSIN": handle_ast_trigonometric_arc_sin,
630
+ "AST_FUNCTION_ARCSINH": handle_ast_trigonometric_arc_sinh,
631
+ "AST_FUNCTION_ARCTAN": handle_ast_trigonometric_arc_tan,
632
+ "AST_FUNCTION_ARCTANH": handle_ast_trigonometric_arc_tanh,
633
+ "AST_FUNCTION_CEILING": handle_ast_function_ceiling,
634
+ "AST_FUNCTION_COS": handle_ast_trigonometric_cos,
635
+ "AST_FUNCTION_COSH": handle_ast_trigonometric_cosh,
636
+ "AST_FUNCTION_COT": handle_ast_trigonometric_cot,
637
+ "AST_FUNCTION_COTH": handle_ast_trigonometric_coth,
638
+ "AST_FUNCTION_CSC": handle_ast_trigonometric_csc,
639
+ "AST_FUNCTION_CSCH": handle_ast_trigonometric_csch,
640
+ "AST_FUNCTION_DELAY": handle_ast_function_delay,
641
+ "AST_FUNCTION_EXP": handle_ast_function_exp,
642
+ "AST_FUNCTION_FACTORIAL": handle_ast_function_factorial,
643
+ "AST_FUNCTION_FLOOR": handle_ast_function_floor,
644
+ "AST_FUNCTION_LN": handle_ast_function_ln,
645
+ "AST_FUNCTION_LOG": handle_ast_function_log,
646
+ "AST_FUNCTION_MAX": handle_ast_function_max,
647
+ "AST_FUNCTION_MIN": handle_ast_function_min,
648
+ "AST_FUNCTION_PIECEWISE": handle_ast_function_piecewise,
649
+ "AST_FUNCTION_POWER": handle_ast_function_power,
650
+ "AST_FUNCTION_QUOTIENT": handle_ast_divide_int,
651
+ "AST_FUNCTION_RATE_OF": handle_ast_function_rate_of,
652
+ "AST_FUNCTION_ROOT": handle_ast_function_root,
653
+ "AST_FUNCTION_REM": handle_ast_function_rem,
654
+ "AST_FUNCTION_SEC": handle_ast_trigonometric_sec,
655
+ "AST_FUNCTION_SECH": handle_ast_trigonometric_sech,
656
+ "AST_FUNCTION_SIN": handle_ast_trigonometric_sin,
657
+ "AST_FUNCTION_SINH": handle_ast_trigonometric_sinh,
658
+ "AST_FUNCTION_TAN": handle_ast_trigonometric_tan,
659
+ "AST_FUNCTION_TANH": handle_ast_trigonometric_tanh,
660
+ "AST_INTEGER": handle_ast_integer,
661
+ "AST_LAMBDA": handle_ast_lambda,
662
+ "AST_LOGICAL_AND": handle_ast_logical_and,
663
+ "AST_LOGICAL_IMPLIES": handle_ast_logical_implies,
664
+ "AST_LOGICAL_NOT": handle_ast_logical_not,
665
+ "AST_LOGICAL_OR": handle_ast_logical_or,
666
+ "AST_LOGICAL_XOR": handle_ast_logical_xor,
667
+ "AST_MINUS": handle_ast_minus,
668
+ "AST_NAME": handle_ast_name,
669
+ "AST_NAME_AVOGADRO": handle_ast_name_avogadro,
670
+ "AST_NAME_TIME": handle_ast_name_time,
671
+ "AST_ORIGINATES_IN_PACKAGE": handle_ast_originates_in_package,
672
+ "AST_PLUS": handle_ast_plus,
673
+ "AST_POWER": handle_ast_function_power,
674
+ "AST_RATIONAL": handle_ast_rational,
675
+ "AST_REAL": handle_ast_real,
676
+ "AST_REAL_E": handle_ast_real,
677
+ "AST_RELATIONAL_EQ": handle_ast_relational_eq,
678
+ "AST_RELATIONAL_GEQ": handle_ast_relational_geq,
679
+ "AST_RELATIONAL_GT": handle_ast_relational_gt,
680
+ "AST_RELATIONAL_LEQ": handle_ast_relational_leq,
681
+ "AST_RELATIONAL_LT": handle_ast_relational_lt,
682
+ "AST_RELATIONAL_NEQ": handle_ast_relational_neq,
683
+ "AST_TIMES": handle_ast_times,
684
+ }
685
+ return commands[AST_TYPES[node.getType()]](node=node, func_arguments=func_arguments)
686
+
687
+
688
+ def parse_sbml_math(node: ASTNode) -> tuple[str, list[str]]:
689
+ func_arguments: list[Any] = []
690
+ body = _handle_ast_node(node=node, func_arguments=func_arguments)
691
+ return body, sorted(set(func_arguments))