Large-Module Audit¶
Thirty-three modules in mixle exceed 1,500 lines. Size alone is not a defect, and this audit is not a
mandate to split them. Its purpose (worklist A1.7) is to record, for each large module, what it owns, the
state it carries, the optional dependencies it touches, its hot paths, its serialization hooks, and where a
safe extraction boundary lies — so that a future change can be scoped without a blind refactor.
The governing rule, restated from Support Policy: refactor a large module only where it removes a demonstrated defect or enables isolated testing. Do not split stable numerical code merely to satisfy a line-count target — the EM kernels and forward/backward recursions below are load-bearing and bit-checked, and re-slicing them risks a correctness regression for no user-visible gain.
The set of modules audited here is pinned by mixle/tests/large_module_audit_test.py: a new module that
crosses 1,500 lines, or an audited entry that is deleted, fails that test until this page is updated.
How to read an entry¶
Responsibilities — what the module owns.
Stateful globals — module-level mutable/registry state (the first thing to check before extraction).
Optional imports — heavy dependencies reached lazily; base import must not require them.
Hot paths — the numerically load-bearing routines; treat as bit-checked, change with parity tests.
Serialization — round-trip hooks (
to_json/from_json/ encoders); a schema-visible surface.Extraction boundary — the safe seam, or “leave as-is” when no clean seam removes a defect.
Latent sequence and mixture families¶
These follow the canonical six-type contract (Distribution / Sampler / Accumulator / AccumulatorFactory /
Estimator / DataEncoder). Their bulk is the vectorized seq_update / seq_log_density EM machinery and,
for several, compiled Numba kernels. They share one extraction principle: the compiled kernels and the data
encoder are the only clean seams; the distribution/estimator pair is a single numerical unit.
mixle/stats/latent/hidden_markov.py(5,308)Responsibilities: the principal HMM path — distribution, scaled forward/backward, Baum-Welch EM, terminal/terminal-value likelihoods, Dirichlet chain prior.
Stateful globals: only
TypeVars (T,E1,E2…); no mutable registry.Optional imports: none at this layer (the compiled kernels live in
_hidden_markov_numba_kernels.py, already a separate module).Hot paths:
_hmm_forward_ll,seq_log_density,seq_update,kernel, the Numba route.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: the Numba kernels are already extracted. The terminal-state and terminal-value likelihood blocks are the next candidate seam if a defect ever localizes there; absent that, leave as-is — this is the most parity-tested numerical code in the tree.
mixle/stats/latent/tree_hidden_markov_model.py(2,990)Responsibilities: tree-structured HMM; Numba forward/backward, Baum-Welch, posteriors, Viterbi.
Stateful globals:
TypeVars and shape aliases only.Optional imports: none (Numba kernels inline as module functions
numba_*).Hot paths:
numba_seq_log_density,numba_baum_welch,numba_posteriors,numba_viterbi.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: the
numba_*kernel group is the clean seam (mirrorhidden_markov’s split into a_..._numba_kernelsmodule) — worth doing only alongside a kernel change.
mixle/stats/latent/structured_hmm.py(3,320)Responsibilities: HMM with pluggable transition operators (dense / low-rank / sparse / block-diagonal / banded), 24 classes.
Stateful globals:
_DENSE_FB_NUMBA(compiled-kernel handle).Optional imports:
jax,numba.Hot paths: forward/backward,
seq_update,seq_log_density,logsumexp.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: the
TransitionOperatorfamily (already an internal class hierarchy) is the natural module split — a genuine isolated-testing win, low numerical risk.
mixle/stats/latent/lookback_hidden_markov_model.py(2,096)Responsibilities: the lookback-window HMM — a typed rewrite of a since-removed untyped sibling module — forward/backward and Baum-Welch EM over a bounded lookback horizon, terminal-state/value likelihoods, and (as of the conjugate-prior fix) a Dirichlet chain prior mirroring
hidden_markov.py’s own MAP path.Stateful globals: only
TypeVars (T,E0,E1); no mutable registry.Optional imports: none at this layer (the compiled kernels live in
_hidden_markov_numba_kernels.py, shared withhidden_markov.py).Hot paths:
seq_log_density,seq_update/seq_update_engine, and the MAP branch insideestimate(_hmm_map_probsplus Dirichlet posterior propagation, added alongsideget_prior/set_prior/model_log_density).Serialization:
dist_to_encoder/seq_encode; two backward-compatible aliases (LookbackHiddenMarkovModelAccumulator/...AccumulatorFactory) at module scope.Extraction boundary: leave as-is; the prior/MAP machinery just added mirrors
hidden_markov.py’s own inline placement rather than introducing a separable module — the file crossed 1,500 lines to reach that parity, not through unrelated growth.
mixle/stats/sequences/markov_chain.py(2,755)Responsibilities: Markov chain distribution/estimator, Dirichlet prior, stationary distribution, gradient-fit state.
Stateful globals:
TypeVars only.Optional imports: none.
Hot paths: forward,
seq_update,seq_log_density,kernel.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: leave as-is; the gradient-fit state (
_MarkovChainGradientFitState) is the only separable piece and is small.
mixle/stats/latent/mixture.py(2,348)Responsibilities: the general finite mixture — responsibilities, weight prior, EM.
Stateful globals:
TypeVars only.Optional imports: none (Numba referenced through the compute layer).
Hot paths: responsibility
logsumexp,seq_update,seq_log_density,kernel.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: leave as-is; the prior-construction helpers (
mixture_priorand friends) could move to a_priorshelper but that is cosmetic, not defect-driven.
mixle/stats/latent/lda.py(1,966) andmixle/stats/latent/labeled_lda.py(1,837)Responsibilities: LDA and label-supervised LDA — variational E-step, alpha updates.
Stateful globals: shape aliases only; no registry.
Optional imports: none.
Hot paths: variational fixed point,
seq_update,seq_log_density.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: the shared alpha-update math (
update_alphaexists in both) is a real duplication seam — a small shared helper would remove copy drift; safe, defect-adjacent.
mixle/stats/combinator/conditional.py(1,965)Responsibilities: conditional-distribution combinator (feature → response) and its accumulation.
Stateful globals: shape aliases only.
Optional imports: none.
Hot paths:
seq_update,seq_log_density,kernel.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: leave as-is; the two module-level stat helpers are already factored.
mixle/stats/graphs/temporal_graph_grammar.py(4,424)Responsibilities: temporal graph-grammar family (37 classes: motifs, labeled/unlabeled variants).
Stateful globals:
_EPSonly.Optional imports: none at import (graph backends reached lazily).
Hot paths: emission log-likelihood,
seq_update,seq_log_density.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: the labeled vs unlabeled variant families are separable, but they share the motif and alignment helpers; split only if a variant grows an independent defect surface.
mixle/stats/latent/integer_hidden_association.py(1,843)Responsibilities: integer hidden-association models over grouped-count word sets.
Stateful globals: encoding/statistic
TypeVars (E0–E4,SS1,SS2) only, plus the engine-kernel registration performed by_register_int_hidden_association_engine_kernel.Optional imports: Numba, reached through the compute layer.
Hot paths:
seq_log_density,seq_update,seq_update_engine, and thenumba_seq_log_density/numba_seq_updatepair.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: the
numba_*kernels are the only clean seam, as elsewhere in this section; the distribution/estimator pair is one numerical unit. Leave as-is absent a defect.
mixle/stats/latent/integer_probabilistic_latent_semantic_indexing.py(1,723)Responsibilities: integer PLSI — the EM fixed point over document/topic/word factors.
Stateful globals:
T1/SS1aliases, plus_register_int_plsi_engine_kernel’s registration.Optional imports: Numba, through the compute layer.
Hot paths:
fast_seq_log_density/fast_seq_updateand theirseq_*entry points.Serialization:
dist_to_encoder/seq_encode;IntegerPLSIEncodedDatais the payload.Extraction boundary:
IntegerPLSIEncodedDataand thefast_*kernels separate cleanly from the estimator; a real seam, worth taking only with a defect that localizes there.
mixle/stats/latent/heterogeneous_pcfg.py(1,828)Responsibilities: PCFG with heterogeneous terminal emissions — inside/outside recursions, termination certification, quantized index construction.
Stateful globals: none.
Optional imports: none at this layer.
Hot paths:
seq_log_density,seq_update,backend_seq_log_density.Serialization:
dist_to_encoder/seq_encode.Extraction boundary:
PCFGTerminationCertificateand_HeterogeneousPCFGQuantizedIndexBuilderare already self-contained and are the seam if one is ever needed; the recursions themselves are a single unit.
mixle/stats/sequences/integer_markov_chain.py(1,972)Responsibilities: integer Markov chains with optional lagged transitions, including the explicitly non-generative scoring mode (
NonGenerativeIntegerMarkovChainError).Stateful globals:
E1/E2/SS1/SS2aliases only.Optional imports: none.
Hot paths:
seq_log_density,seq_update,seq_update_engine,backend_seq_log_density.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: leave as-is. The lag handling threads through encode, score and update together; separating it would split one contract across two modules.
mixle/stats/multivariate/multivariate_gaussian.py(1,911)Responsibilities: full-covariance Gaussian six-type contract, the covariance ridge and its repair disclosure, the robust Cholesky self-heal, the opt-in conditioning receipt, and the conditioning-gated shift-anchored moment track.
Stateful globals:
_LAST_REPAIR(a one-slot channel from_robust_cho_factorto the constructor, drained immediately).Optional imports:
scipy.linalg(required at this layer),scipy.statslazily for cdf/quantile.Hot paths:
seq_log_density,seq_update,_robust_cho_factor,_anchored_pooled_covariance,backend_stacked_sufficient_statistics.Serialization:
__pysp_getstate__/__pysp_setstate__(parameters only; derived caches recomputed),dist_to_encoder/seq_encode, andMultivariateGaussianSuffStat.__reduce__.Extraction boundary: the anchored-moment helpers (
_needs_anchor,_consistent_anchored_moments,_anchored_mean_offset,_anchored_pooled_covariance) are the one clean seam, shared in spirit with the diagonal and univariate Gaussian families.
mixle/stats/multivariate/diagonal_gaussian.py(1,624)Responsibilities: diagonal-covariance Gaussian six-type contract, per-coordinate variance floor and its repair disclosure, and the same conditioning-gated shift-anchored moment track.
Stateful globals: none.
Optional imports:
scipy.statslazily for cdf/quantile.Hot paths:
seq_log_density,seq_update,_anchored_pooled_variances.Serialization:
dist_to_encoder/seq_encodeandDiagonalGaussianSuffStat.__reduce__.Extraction boundary: the anchored-moment helpers, jointly with the full-covariance module’s.
mixle/stats/multivariate/integer_multinomial.py(1,586)Responsibilities: integer-keyed multinomial over a bounded support.
Stateful globals:
SS0/D/E0/Ealiases only.Optional imports: none.
Hot paths:
seq_log_density,seq_update,seq_update_engine.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: leave as-is; the six-type contract is already the minimum unit here.
mixle/stats/combinator/sequence.py(1,679)Responsibilities: iid sequence laws plus the explicitly non-generative sequence score modes (
NonGenerativeSequenceError), including the length-support reasoning.Stateful globals:
T/E1/E2/Ealiases and the two proof limits_INFINITE_INTEGER_LENGTH_SUPPORTS,_FINITE_LENGTH_PROOF_LIMIT(constants, not mutable state).Optional imports: none.
Hot paths:
seq_log_density,seq_update,backend_seq_log_density,backend_stacked_log_density,expected_log_density.Serialization:
dist_to_encoder/seq_encode.Extraction boundary: the length-support proof helpers are the one separable piece; the generative and score-only paths must stay together, since their divergence is the contract.
mixle/stats/bayes/conjugate.py(1,669)Responsibilities: conjugate-prior posteriors derived from the exponential-family map, one class per conjugate pair, plus the
_NO_CLOSED_FORMfallback marker.Stateful globals:
_NO_CLOSED_FORM(a sentinel).Optional imports:
scipy(special functions), reached lazily.Hot paths: posterior updates and
point_estimate; per-observation, not per-batch.Serialization: posterior parameters round-trip through the owning distribution.
Extraction boundary: one module per conjugate family would be a clean split, but the shared exponential-family derivation is what keeps them consistent — leave as-is.
Probabilistic-programming surface¶
mixle/ppl/inference.py(4,490)Responsibilities: posterior inference for the PPL — conjugate, Laplace, VI, MCMC routes.
Stateful globals: several registries —
_CONJUGATE,_CONJ_LOGM,_HIERARCHICAL,_PRIOR_DICT_BUILDERS,_EXPECTED_PRIOR_FAMILY(dispatch tables; the first thing to preserve).Optional imports:
torch.Hot paths:
seq_log_density,kernel(through the fitted posteriors).Serialization:
dist_to_encoder/seq_encode.Extraction boundary: the conjugate-posterior registry (tables + their builders) is a clean module of its own, separable from the Laplace/VI/MCMC numeric routes — a real isolated-testing win. Move the registries as a unit so dispatch stays in one place.
mixle/ppl/core.py(3,317)Responsibilities: the PPL authoring DSL (
Field/Group/Net/Conv/Transformer) and the fitter registry.Stateful globals:
_ROUTE_CAVEATS,_CMP,_RESIDUALplus the fitter registry populated byregister_fitter.Optional imports:
torch.Hot paths:
forward,seq_log_density.Extraction boundary: the neural predictors (
_NeuralPredictor/Net/Conv/Transformer) are the torch-touching subset and a natural split from the pure-DSL field/group core.
Compiled-kernel code generation¶
mixle/stats/compute/fused_codegen.py(2,438)Responsibilities: the fused-kernel source generator — per-family
LeafTemplates (scalar, vector, matrix, tabulated, categorical, chain), plan analysis (analyze/fusible), source emission for the one-pass scorer and E-step (sequential and chunk-parallel prange variants), the secure disk-cached_njitloader, and the data/parameter marshalling that feeds generated signatures.Stateful globals: the
_TEMPLATESregistry (append-ordered; matching is first-hit, so registration order is part of dispatch semantics) and the_COMPILED/_ESTEP_COMPILEDkernel caches keyed by(plan.signature, parallel)— plus the on-disk module cache underMIXLE_FUSED_CACHE_DIRwith its ownership/symlink checks.Optional imports:
numba— reached lazily inside_njit; importing this module must stay numba-free (the freeze-rollup resolver depends on that, guarded byHAS_NUMBAat its call site).Hot paths: every generated
_fused/_estepkernel; parity is pinned bygenerated_kernel_parity_test.py,fused_codegen_test.py,fused_parallel_test.py(ULP / bit-stability receipts), andfused_chain_test.py— treat templaterow/accfragments as bit-checked and change them only with those suites green.Serialization: none — kernels are runtime artifacts; the disk cache is a per-user performance cache keyed by source digest, never a schema surface.
Extraction boundary: the leaf templates (registrations plus their param/table builders) are the clean seam — they are data, not machinery, and moving them to a
_templatesmodule would halve the file without touching emission. The emitter + marshalling + cache trio is a single numerical unit; split only against a demonstrated defect.
Infrastructure and facade¶
mixle/lifecycle.py(1,702)Responsibilities: the
Modelfacade (fit/deploy/load, provenance and integrity checks) andpropose— automatic model-family selection and its held-out verified-frontier scoring.Stateful globals: none (module-level constants only).
Optional imports: none directly (delegates tabular record handling to
mixle.data.sources.pandas_source, reached only when the caller’s data is already pandas).Serialization:
Model.deploy/Model.load— the JSON-first, pickle-fallback artifact format, including themodel_sha256integrity check and the_fit_provenance/_numerical_repairsenvelope re-attachment on decode.Extraction boundary:
Modelandproposeare two largely independent halves sharing only the tabular-record helpers (_tabular_recordset al.); a real seam, but split only if one half’s test surface needs isolating from the other’s.
mixle/inference/estimation.py(2,422)Responsibilities: the
optimize/fit/best_offront door — data encoding, model proposal handoff (_maybe_structured_model), the fused/standard EM drivers, and the schedule/objective plumbing.Stateful globals: none (module-level constants only).
Optional imports:
torch(gradient-fit path), reached lazily.Hot paths:
optimize’s fused-step loop (_local_fused_step/_engine_fused_step) — change with LL-parity tests against the standard loop.Serialization: none directly (delegates to the model’s encoders).
Extraction boundary: the structure-proposal gate (
_maybe_structured_model) and the EM-driver loops are separable seams; extract only to remove a demonstrated defect, per the audit’s own rule.
mixle/inference/glm.py(1,895)Responsibilities: the GLM front door (
glm) across the exponential-family link/family set and its robust standard-error variants (HC0-HC3, with their leverage/rank diagnostics),robust_regression(Huber/Tukey IRLS and its degenerate-fit breakdown disclosure), the penalized-regression trio (ridge_regression/elastic_net/lasso), andquantile_regression.Stateful globals: none (module-level constants only – the floors/tolerances/fractions gating the HC2/HC3 leverage guard and the robust-regression breakdown disclosure; none mutable).
Optional imports: none.
Hot paths:
glm’s IRLS loop and its HC2/HC3 leverage computation (rank-masking is parity-sensitive – see the campaign-eight/D-0208 fix to how it handles a rank-deficient design);robust_regression’s own IRLS loop and its breakdown-disclosure signals (_robust_weight_collapse/_robust_response_point_mass, also D-0208).Serialization: none (
GLMResult/RegressionFit/PenalizedResultare plain, non-round-tripped dataclasses).Extraction boundary:
robust_regressionand its breakdown-disclosure helpers (_response_robust_scalethrough_robust_breakdown_explanation) are already a self-contained seam fromglm, the penalized-regression trio, andquantile_regression. The file crossed 1,500 lines through three consecutive rounds of disclosure-heuristic repair on that one function family (D-0208’s own campaign-eight fix wave), not through unrelated growth elsewhere – extract only if that family needs an isolated test surface of its own, not as a line-count exercise.
mixle/stats/__init__.py(2,426)Responsibilities: the
mixle.statsfacade — lazy__getattr__re-exports, capability registration, and theload_models/dump_modelsmodel-collection serialization entry points.Stateful globals:
_INTERNAL_SUFFIXESplus the lazy-export and capability tables.Optional imports: none (that is the point — the facade must import in a bare environment).
Serialization:
to_json/from_json(load_models/dump_models).Extraction boundary: the builtin-compute-metadata and lazy-capability registration blocks (
_register_builtin_compute_metadata/_register_lazy_module_capabilities) can move to a_registrationhelper, leaving__init__as thin re-export glue. Low risk, improves import readability; do it when the registration tables next change.
mixle/utils/automatic/profiling.py(3,301)Responsibilities: automatic-modeling data profiling — marginal/pairwise structure detection.
Stateful globals: tuning constants
_MIXTURE_EM_CAP,_NUMERIC_MODEL_MARGIN_BITS,GOF_ABSTAIN_PVALUE(thresholds, not mutable state).Optional imports: none.
Extraction boundary: the goodness-of-fit / entropy scoring helpers are separable from the profile dataclasses; a defect-neutral tidy, not urgent.
mixle/utils/parallel/planner.py(2,345)Responsibilities: device/placement/sharding planning and the encoded-data backend registry.
Stateful globals: the encoded-data backend registry (via
register_encoded_data_backend).Optional imports:
dask,torch.Serialization:
to_json/from_json(placement/plan round-trip — schema-visible).Extraction boundary: the encoded-data backend registry and its backends are separable from the placement/calibration solver; a real seam, but touch it only with a distributed-path change.
mixle/stats/compute/declarations.py(2,303)Responsibilities: distribution declarations (parameter/statistic specs, exponential-family specs) and the Numba-lowering validation.
Stateful globals:
_NUMBA_INFIX_OPS,_NUMBA_FUNC_OPS,_KNOWN_PARAMETER_CONSTRAINTS,_SHARED_STACKED_PARAMETER_CONSTRAINTS(lowering tables).Optional imports: none.
Extraction boundary: the Numba-lowering tables and their validation are separable from the spec dataclasses; split when the lowering rules next grow.
mixle/stats/compute/pdist.py(2,068)Responsibilities: the root contracts — the six-type ABCs,
DensitySemantics, and the error types (ContractError,EnumerationError,KeyValidationError).Stateful globals:
SSalias and_KEY_ATTRS.Optional imports:
inspectandmixlesubmodules, deferred to avoid import cycles.Hot paths: none of its own; it defines the signatures every hot path implements.
Serialization:
from_jsonand thedist_to_encoder/seq_encodecontract itself.Extraction boundary: do not split. Nearly every module in the tree imports this one, so a split multiplies the import-cycle surface that
doe_task_models_clean_import_testguards. The error classes could move if that test ever forces it, and nothing else should.
mixle/stats/compute/fused_kernels.py(1,803)Responsibilities: fused Numba kernels for mixture estimation over heterogeneous data, and the per-leaf builders that generate them.
Stateful globals:
_BUILDERS(the leaf-builder registry) and_NEG_INF.Optional imports: Numba via the compute layer,
scipy,concurrent(parallel build),os.Hot paths:
build_kernel,seq_log_density,seq_component_log_density, and the_pair_kernels/_sequence_kernel/_optional_kernelgenerators.Serialization:
CompiledEncodingis the compiled-payload boundary, not a schema surface.Extraction boundary: the
_LeafBuildersubclasses are one clean seam per leaf family and the registry makes the split mechanical; the codegen core should stay whole.
mixle/ppl/field.py(1,931)Responsibilities: latent Gaussian fields observed through many proxies — kernels (RBF/Matern/great-circle/anisotropic), the field system, proxy likelihoods, and posterior readout.
Stateful globals:
_SPARSE_SOLVE_DETECTORS(a detector registry).Optional imports:
torchandscipy-backed sparse solves, both reached lazily.Hot paths: kernel assembly and the sparse/dense posterior solve.
Serialization: field and proxy parameters round-trip through the owning system.
Extraction boundary: the
FieldKernelhierarchy is fully separable fromFieldSystemand theProxyfamily; a genuine three-way seam, and the first place to split if this module grows.
mixle/relations.py(1,825)Responsibilities: relations over structured spaces enumerated by residual — shortest path, assignment, spanning tree, edit distance, Viterbi path, best-subset regression.
Stateful globals: none.
Optional imports:
scipy(sparse/optimization routines), lazily.Hot paths: each relation’s enumeration loop; the residual ordering is the shared contract.
Serialization:
Solution/Designcarry the round-tripped state.Extraction boundary: one module per relation is a clean, obvious split, held together only by the shared
Relationbase and its ordering guarantee. Defect-neutral; do it when one grows.