core.py — Computational Backend
The core module contains all numerical computation for ToFUL.
The frontend (app.py) calls the public functions at the bottom of
this module; it imports nothing from SciPy or NumPy directly.
Architecture
toful_parser.py
└── normalise_for_eval() ← clean user input
└── build_safe_dict() ← eval namespace
core.py
├── _build_safe_dict() ← canonical eval namespace
├── _cached_compile() ← AST compiled once per expression
├── _eval_scalar() ← scalar evaluation
├── _eval_array() ← vectorised NumPy evaluation
│
├── Convergence cascade (discrete)
│ ├── _wynn_epsilon()
│ ├── _aitken_delta2()
│ ├── _cohen_villegas_zagier()
│ └── _sum_series_with_acceleration()
│
├── Quadrature (continuous)
│ ├── _gauss_laguerre_integrate()
│ ├── _gauss_hermite_integrate()
│ ├── _mpmath_integrate()
│ └── _quadrature_integrate() ← dispatch
│
├── Symbolic path
│ └── _try_sympy_moment()
│
├── Validation
│ ├── validate_drv_probabilities() ← public
│ └── validate_crv_pdf() ← public
│
├── Moment computation
│ ├── _compute_drv_moment()
│ ├── _compute_crv_moment()
│ └── compute_moments_parallel() ← public
│
├── Statistical summary
│ └── compute_statistical_summary() ← public
│
└── Range parsing
├── parse_range_input() ← public
└── parse_continuous_bound() ← public
Data Classes
- class core.SeriesPattern(kind, params, description='')[source]
Detected pattern of a discrete sequence.
- class core.SeriesAnalysis(value, converged, terms_used, method, info, partial_sums=<factory>, term_values=<factory>)[source]
Diagnostic output from a single discrete series computation.
- Parameters:
- class core.ValidationResult(is_valid, message, integral_or_sum, analysis=<factory>)[source]
Returned by the probability validators.
- class core.MomentResult(order, reference, value, method, converged, terms_or_nodes, info)[source]
Result for a single moment computation.
- Parameters:
Public API
Validation
- core.validate_drv_probabilities(expr_str, x_values, is_infinite=False, tol=0.01, extra=None)[source]
Validate that a discrete PMF sums to 1 and has no negative values.
- Parameters:
expr_str (str) – Eval-normalised PMF expression.
x_values (array-like) – Support values (finite window or extended series for infinite).
is_infinite (bool) – Whether the support is effectively unbounded beyond x_values.
tol (float) – Tolerance on
abs(sum - 1.0). Loosened for non-converged infinite series due to truncation error.extra (dict, optional)
- Return type:
- core.validate_crv_pdf(expr_str, bounds, precision=8, extra=None)[source]
Validate that a continuous PDF integrates to 1 and is non-negative.
Quadrature rule selected based on the integration domain: - Finite [a, b] : scipy.integrate.quad (Gauss-Kronrod, adaptive) - Semi-infinite [0, inf): Gauss-Laguerre nodes (exact for exp weight) - Doubly-infinite : Gauss-Hermite nodes (exact for Gaussian weight) - High precision (>12dp): mpmath tanh-sinh quadrature
Moment Computation
- core.compute_moments_parallel(expr_str, support_or_bounds, max_order, a, is_crv, is_infinite=False, precision=8, tol=1e-12, extra=None, max_workers=4)[source]
Compute moments of orders 1 through max_order in parallel.
Moment computations for different orders are independent. All orders are submitted to a ThreadPoolExecutor; results are collected as they complete. For max_order <= 2 the threading overhead is avoided and computation is sequential.
- Parameters:
expr_str (str) – Eval-normalised PMF/PDF expression.
support_or_bounds (np.ndarray or (float, float)) – For DRV: array of support values. For CRV: (lower, upper) tuple.
max_order (int) – Compute moments mu_1 through mu_{max_order}.
a (float) – Reference point (0=raw, mu=central, other=custom).
is_crv (bool) – True for continuous RV, False for discrete.
is_infinite (bool) – For DRV: whether support is unbounded beyond support array.
precision (int) – Target decimal places (affects quadrature tolerance and mpmath).
tol (float) – Convergence tolerance for discrete series.
extra (dict, optional) – Extra variable bindings.
max_workers (int) – Thread pool size.
- Return type:
dict mapping int -> MomentResult
Statistical Summary
- core.compute_statistical_summary(mean, central_moments)[source]
Derive variance, standard deviation, skewness, and kurtosis from central moments (moments computed about the mean).
- Standard formulae:
variance = mu_2 std_dev = sqrt(abs(mu_2)) skewness = mu_3 / sigma^3 kurtosis = mu_4 / sigma^4 excess_kurtosis = kurtosis - 3
- Parameters:
- Return type:
Range Parsing
- core.parse_range_input(range_input)[source]
Parse a discrete range string into a NumPy array of support values.
- Accepts:
“1, 2, 3, 4, 5” -> finite support “0, 1, 2, 3, …” -> infinite arithmetic series (extended to _MAX_SERIES_TERMS) “1, 2, 4, 8, …” -> infinite geometric series
- Parameters:
range_input (str) – Range string, already cleaned by toful_parser.normalise_range_input().
- Return type:
(values_array, is_infinite, pattern_description)
- Raises:
ValueError – If the string cannot be parsed as a comma-separated list of numbers.
Utilities
- core.to_subscript(n)[source]
Convert a non-negative integer to its Unicode subscript string.
Examples
>>> to_subscript(12) '12' # rendered as subscript digits
- core.detect_series_pattern(values)[source]
Detect whether seed values form an arithmetic or geometric sequence.
- core.generate_extended_series(pattern, max_terms=500)[source]
Generate a NumPy array of the first max_terms values matching the pattern.
- Parameters:
pattern (SeriesPattern)
max_terms (int)
- Return type:
np.ndarray
Convergence Algorithm Reference
The following internal functions implement the convergence acceleration cascade. They are not part of the public API but are documented here for contributors and advanced users.
_wynn_epsilon(partial_sums)Wynn ε-algorithm. Builds a recursive epsilon-table from the list of partial sums and returns the best limit estimate from the even-column diagonal.
Returns
(estimate, converged, info_string)._aitken_delta2(s0, s1, s2)Aitken Δ² three-point extrapolation. Returns the extrapolated limit from three consecutive partial sums.
_cohen_villegas_zagier(expr_str, n_terms)Cohen-Villegas-Zagier algorithm for alternating series. Computes near-machine-precision estimate in exactly
n_termsevaluations.Returns
(estimate, True, info_string)._sum_series_with_acceleration(expr_str, x_values, r, a, tol)Main discrete summation engine. Evaluates
Σ (x-a)^r · f(x)overx_valuesand applies the full convergence cascade.Returns a
SeriesAnalysisinstance.
Quadrature Reference
_gauss_laguerre_integrate(func, n=64)Gauss-Laguerre quadrature for \(\int_0^\infty f(x)\,dx\). Uses 64 nodes. Returns
(estimate, error_estimate)._gauss_hermite_integrate(func, n=64)Gauss-Hermite quadrature for \(\int_{-\infty}^{\infty} f(x)\,dx\). Uses 64 nodes. Returns
(estimate, error_estimate)._mpmath_integrate(func, lower, upper, precision)mpmath tanh-sinh (double-exponential) quadrature. Active when Calc precision ≥ 13. Returns
(estimate, error_estimate, "mpmath-tanh-sinh")._quadrature_integrate(func, lower, upper, precision, ...)Dispatch function. Selects the best quadrature method based on domain and precision, cross-checks results, returns
(value, error, method_name).
Configuration Constants
_MPMATH_THRESHOLD = 12 # Calc precision above which mpmath activates
_MAX_SERIES_TERMS = 500 # Hard cap on infinite-series truncation
_CONVERGENCE_TOL = 1e-12 # Default convergence tolerance
_GAUSS_NODES = 64 # Gauss-Laguerre / Hermite quadrature nodes
Legacy Compatibility
The following classes and function from the original codebase are retained as thin shims over the new API. New code should use the public functions above directly.
- class core.InfiniteSeriesHandler[source]
Legacy shim — use detect_series_pattern() and generate_extended_series().
- class core.EnhancedProbabilityValidator[source]
Legacy shim — use validate_drv_probabilities() / validate_crv_pdf().
See also
toful_parser.py — Input Normalisation — input normalisation API
Convergence Methods — the mathematics behind each method