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.
- odeanalysis/__init__.py +296 -0
- odeanalysis/_api_policy.py +179 -0
- odeanalysis/_assumptions.py +89 -0
- odeanalysis/_block_common.py +106 -0
- odeanalysis/_formal_gauge.py +115 -0
- odeanalysis/_local.py +166 -0
- odeanalysis/_moser.py +271 -0
- odeanalysis/_power_simplify.py +32 -0
- odeanalysis/_spectral.py +215 -0
- odeanalysis/_symbolic_compare.py +16 -0
- odeanalysis/_symbolic_errors.py +19 -0
- odeanalysis/_zero.py +28 -0
- odeanalysis/analytic_continuation.py +343 -0
- odeanalysis/bell.py +87 -0
- odeanalysis/block_decomposition.py +1144 -0
- odeanalysis/canonical.py +471 -0
- odeanalysis/certified_continuation.py +160 -0
- odeanalysis/diagnostics.py +17 -0
- odeanalysis/dominance.py +134 -0
- odeanalysis/factorization.py +88 -0
- odeanalysis/formal.py +1028 -0
- odeanalysis/formal_basis.py +1009 -0
- odeanalysis/frobenius.py +349 -0
- odeanalysis/fuchsian.py +400 -0
- odeanalysis/interchange.py +604 -0
- odeanalysis/interoperability.py +143 -0
- odeanalysis/irregular.py +250 -0
- odeanalysis/kovacic.py +478 -0
- odeanalysis/levelt.py +679 -0
- odeanalysis/local_analysis.py +386 -0
- odeanalysis/local_structure.py +290 -0
- odeanalysis/matrix_series.py +357 -0
- odeanalysis/newton.py +501 -0
- odeanalysis/operator.py +193 -0
- odeanalysis/parameter_wkb.py +92 -0
- odeanalysis/py.typed +0 -0
- odeanalysis/series.py +199 -0
- odeanalysis/singularities.py +279 -0
- odeanalysis/stokes.py +782 -0
- odeanalysis/system.py +347 -0
- odeanalysis/system_analysis.py +615 -0
- odeanalysis/transition_loci.py +302 -0
- odeanalysis/turning.py +516 -0
- odeanalysis/wronskian.py +110 -0
- odeanalysis-0.1.0.dist-info/METADATA +180 -0
- odeanalysis-0.1.0.dist-info/RECORD +49 -0
- odeanalysis-0.1.0.dist-info/WHEEL +5 -0
- odeanalysis-0.1.0.dist-info/licenses/LICENSE +677 -0
- 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)))
|