odeanalysis 0.1.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 (49) hide show
  1. odeanalysis/__init__.py +296 -0
  2. odeanalysis/_api_policy.py +179 -0
  3. odeanalysis/_assumptions.py +89 -0
  4. odeanalysis/_block_common.py +106 -0
  5. odeanalysis/_formal_gauge.py +115 -0
  6. odeanalysis/_local.py +166 -0
  7. odeanalysis/_moser.py +271 -0
  8. odeanalysis/_power_simplify.py +32 -0
  9. odeanalysis/_spectral.py +215 -0
  10. odeanalysis/_symbolic_compare.py +16 -0
  11. odeanalysis/_symbolic_errors.py +19 -0
  12. odeanalysis/_zero.py +28 -0
  13. odeanalysis/analytic_continuation.py +343 -0
  14. odeanalysis/bell.py +87 -0
  15. odeanalysis/block_decomposition.py +1144 -0
  16. odeanalysis/canonical.py +471 -0
  17. odeanalysis/certified_continuation.py +160 -0
  18. odeanalysis/diagnostics.py +17 -0
  19. odeanalysis/dominance.py +134 -0
  20. odeanalysis/factorization.py +88 -0
  21. odeanalysis/formal.py +1028 -0
  22. odeanalysis/formal_basis.py +1009 -0
  23. odeanalysis/frobenius.py +349 -0
  24. odeanalysis/fuchsian.py +400 -0
  25. odeanalysis/interchange.py +604 -0
  26. odeanalysis/interoperability.py +143 -0
  27. odeanalysis/irregular.py +250 -0
  28. odeanalysis/kovacic.py +478 -0
  29. odeanalysis/levelt.py +679 -0
  30. odeanalysis/local_analysis.py +386 -0
  31. odeanalysis/local_structure.py +290 -0
  32. odeanalysis/matrix_series.py +357 -0
  33. odeanalysis/newton.py +501 -0
  34. odeanalysis/operator.py +193 -0
  35. odeanalysis/parameter_wkb.py +92 -0
  36. odeanalysis/py.typed +0 -0
  37. odeanalysis/series.py +199 -0
  38. odeanalysis/singularities.py +279 -0
  39. odeanalysis/stokes.py +782 -0
  40. odeanalysis/system.py +347 -0
  41. odeanalysis/system_analysis.py +615 -0
  42. odeanalysis/transition_loci.py +302 -0
  43. odeanalysis/turning.py +516 -0
  44. odeanalysis/wronskian.py +110 -0
  45. odeanalysis-0.1.0.dist-info/METADATA +180 -0
  46. odeanalysis-0.1.0.dist-info/RECORD +49 -0
  47. odeanalysis-0.1.0.dist-info/WHEEL +5 -0
  48. odeanalysis-0.1.0.dist-info/licenses/LICENSE +677 -0
  49. odeanalysis-0.1.0.dist-info/top_level.txt +1 -0
odeanalysis/bell.py ADDED
@@ -0,0 +1,87 @@
1
+ """Bell-polynomial utilities used by the formal ODE layer.
2
+
3
+ The complete exponential Bell polynomial is constructed directly from
4
+ integer-partition multiplicities. SymPy exposes the incomplete/partial
5
+ polynomial ``bell(n, k, symbols)``; the direct partition formula avoids
6
+ recomputing the overlapping partial polynomials when the complete polynomial
7
+ is wanted in expanded monomial form.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from collections.abc import Iterable
13
+ from math import factorial
14
+
15
+ import sympy as sp
16
+ from sympy.utilities.iterables import partitions
17
+
18
+
19
+ def complete_exponential_bell_polynomial(
20
+ n: int,
21
+ variables: Iterable[sp.Expr],
22
+ ) -> sp.Expr:
23
+ r"""Return the complete exponential Bell polynomial ``B_n``.
24
+
25
+ The convention is
26
+
27
+ .. math::
28
+
29
+ B_n(x_1,\ldots,x_n)
30
+ = \sum_{\sum i c_i=n}
31
+ \frac{n!}{\prod_i c_i! (i!)^{c_i}}
32
+ \prod_i x_i^{c_i}.
33
+
34
+ The summation is performed directly over integer-partition multiplicity
35
+ dictionaries, so each generic Bell monomial is constructed exactly once.
36
+ """
37
+
38
+ if not isinstance(n, int):
39
+ raise TypeError("n must be an integer")
40
+ if n < 0:
41
+ raise ValueError("n must be nonnegative")
42
+ if n == 0:
43
+ return sp.S.One
44
+
45
+ xs = tuple(sp.sympify(x) for x in variables)
46
+ if len(xs) < n:
47
+ raise ValueError(f"B_{n} requires at least {n} variables")
48
+
49
+ factorials = tuple(factorial(i) for i in range(n + 1))
50
+ n_factorial = factorials[n]
51
+ terms: list[sp.Expr] = []
52
+
53
+ for multiplicities in partitions(n):
54
+ coefficient = n_factorial
55
+ factors: list[sp.Expr] = []
56
+ for part, multiplicity in multiplicities.items():
57
+ coefficient //= factorials[multiplicity]
58
+ coefficient //= factorials[part] ** multiplicity
59
+ factors.append(sp.Pow(xs[part - 1], multiplicity, evaluate=True))
60
+ terms.append(sp.Integer(coefficient) * sp.Mul(*factors))
61
+
62
+ return sp.Add(*terms)
63
+
64
+
65
+ def complete_exponential_bell_via_sympy(
66
+ n: int,
67
+ variables: Iterable[sp.Expr],
68
+ ) -> sp.Expr:
69
+ """Reference construction using SymPy's partial Bell polynomials.
70
+
71
+ This helper is primarily useful for validation and compatibility tests.
72
+ The partition-based :func:`complete_exponential_bell_polynomial` is the
73
+ direct complete-polynomial implementation used by ``odeanalysis``.
74
+ """
75
+
76
+ if not isinstance(n, int):
77
+ raise TypeError("n must be an integer")
78
+ if n < 0:
79
+ raise ValueError("n must be nonnegative")
80
+ if n == 0:
81
+ return sp.S.One
82
+
83
+ xs = tuple(sp.sympify(x) for x in variables)
84
+ if len(xs) < n:
85
+ raise ValueError(f"B_{n} requires at least {n} variables")
86
+
87
+ return sp.Add(*(sp.bell(n, k, xs[: n - k + 1]) for k in range(1, n + 1)))