Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Source repository: https://github.com/EDF-Lab/tam
The first official open-source release of the TAM framework under this structure is 1.2.3.
⚠️ Note: Versions 1.1.1–1.2.2 correspond to internal development milestones and were not publicly released.
0.0.6 corresponds to the legacy
weaklpackage available on PyPI.
[Unreleased]¶
[1.3.2] - 2026-10-01¶
Patch release (tag on main; the latest release on PyPI and Zenodo stays 1.3.1): two crashes fixed. No prediction changes: every model that worked in 1.3.1 gives the same numbers.
Fixed¶
Grouped models predict a frame holding only some of their groups (
StaticTAMwithgroup_col):predictraisedValueError: Length of values (n) does not match length of index (0)anddecompose_predictionreturned NaN. The groups stacked from the frame were paired with the fitted group list by position, and the per-group coefficients were sliced by position in the stacked tensor, so a one-group frame would have used the first group’s coefficients. Prediction and decomposition now use the groups actually present: rows keep the input order and index, and a group never seen in training raises aValueErrornaming it.plot_componentno longer replicates its grid over every group.Silent overflow in log-target quantiles (
predict_quantile,predict_quantiles,predict_median,anomaly_score, mixturecomponent_meansandpredict_mean): a scale prediction far outside the training range gaveexp(...) = infand a silent numpyRuntimeWarning: overflow encountered in exp. The value is stillinf(it is beyond float64, and the columns stay ordered) but it comes with an explicitUserWarningnaming the quantity and the first rows.
1.3.1 - 2026-09-30¶
Patch release: fixes that made some models wrong (formulas with te() or several features in one term) or not reproducible (rbf(), trees).
Predictions change for the models below; everything else is identical to 1.3.0. To get the 1.3.0 behaviour: pip install tam-ml==1.3.0.
Results change¶
Formulas with
te()or several features in one term: they were fitted with mislabelled terms and now fit the formula as written; their errors drop sharply, and the ensembles built on them follow. The THEORY benchmark and its figures are regenerated with 1.3.1.auto_fit(GCV): now fits exactly the model GCV selected. GCV minimises an in-sample criterion, not the holdout error, so holdout results move in both directions.rbf(): centres are seeded and drawn from the whole training set; RBF models change once and are then reproducible.Trees on grouped data (
t(),lt()withgroup_col): splits and leaf counts come from the whole training set; results change, mostly for the better. Ungrouped trees do not change.NeuralTAM (experimental): may change slightly in scripts that fit
rbf()models before it, because both used to share the global torch random generator. A NeuralTAM fitted on its own after the sametorch.manual_seedis unchanged.Fixed-penalty models without these terms are identical to 1.3.0.
Added¶
tam.plot_component(model, data, component, kind="auto"): plots one additive component with a view chosen from its dimension: a curve for one feature, one curve per level forte(x, c), a 3D surface (orkind="heatmap"with the observed points overlaid) forte(x1, x2), evaluated on a regular grid for one group (group=, default the most frequent), a 3D scatter coloured by the contribution forte(x1, x2, x3). Rows with a non-finite contribution are skipped.tam.common.plotting.resolve_component(model, feature, component=None, color_by=None): the component a feature maps to under the new decomposition names.rbf(x, ..., seed=42): seed of the centre sampling (default 42, liken()andt()).
Fixed¶
Terms renamed by position (
StaticTAM._prepare_data): each effect’sfeature_namewas overwritten from the deduplicated feature list by position, so with ate()or several features in one term, the effects after it were relabelled (e.g.c(day_type_week)becametoy) and the fitted model changed, not only the labels (e.g. a national-load model withte(temperature, toy): test RMSE 3254 → 2432). The renaming is removed.decompose_predictionnames components with the newdecomposition_names(): unique feature names are kept, collisions get a basis prefix (s_x,l_x), and a collision that remains (twote()over the same features) gets an occurrence suffix, so no contribution overwrites another.Plotting helpers after the renaming fix:
plot_effect_with_model_and_dataandplot_effect_with_data_decomposedraisedKeyError: 'effect_x1'for a feature inside ate()or used by several effects. They now resolve the feature to its component: the only one using it, the tensor product whose other margin iscolor_by, or the newcomponent=argument; a still-ambiguous feature raises aValueErrorlisting the candidates. Single-component features plot exactly as before.add_base_effectsin AdaptiveTAM and KalmanTAM: the base model’s components were added asl(effect_<feature>), a name that does not exist when two effects share a feature (s(x) + l(x)giveseffect_s_x,effect_l_x), so the model crashed with aKeyError; and with ate(), the renaming bug above fed mislabelled components. The components are now added under theirdecomposition_names()columns.GCV scored a different penalty from the one it stored (
auto_fit,smart_solve_gcv): each trial rescaled a block that already carried the formula’s own weight, so the search scored λ_formula × λ_GCV but stored λ_GCV alone; a laterfit()on the selected weights returned a different model, and with the defaultap=-9the nine highest decades of the search range were unreachable. Each trial block is now rebuilt by the effect at λ = 10^α, exactly asfit()assembles it; the trial weight is restored even if the search raises, and the initial alphas are clipped to the bounds. Models selected byauto_fitchange.GCV scored a slightly different system from the one fitted (
auto_fit): the solver adds a ridge floor1e-6·n·I, GCV added1e-6·I. Both now use one helper (_ridge_floor), so the selected penalties are scored on the modelfit()returns; a negative residual sum of squares from rounding is clamped at 0 instead of folded withabs(). Penalties belowap = -6are dominated by that floor (documented). Models selected byauto_fitcan change; fixed-penalty fits do not.Trees and RBF centres were initialised on a memory probe, not on the training data (
t(),lt(),rbf()): their data-dependent state was set by the first design matrix built, which is the solver’s size probe (one row per group). With 48 half-hourly groups, quantile splits came from 48 points and thesp_alphaleaf counts summed to 48 × n_trees instead of every training row;rbf()centres were drawn from those 48 points.StaticTAMnow callsinitialize_effects()on the full training tensor before any design matrix; a probe or a later chunk never changes that state. Tree, linear-tree and RBF predictions change for grouped models; ungrouped trees were already initialised on the full data and do not change (ungroupedrbf()changes through its new seed only).rbf()centres were not reproducible: they were drawn from the global torch generator, so an RBF model changed with whatever code ran before it (two identical fits could differ).rbf(x, ..., seed=42)now seeds a local generator, and fitting no longer touches the global random state. RBF predictions change once (new, fixed centres).Sparsity-adaptive tree penalty (
t(..., sp_alpha>0)):empirical_countssummed only the first batch axis, so the leaf-density penalty was built from the wrong counts and could not be formed. It now counts every sample and group, one value per leaf in design-matrix order.Linear tree weight (
lt()): assigninglambda_p(as GCV does on every candidate) did not reach the intercept tree and the slope surface, so GCV could not tunelt(). The weight now propagates to both sub-blocks.Dummy date overflow: without
date_col, the internal dummy date was spaced one day apart and ran past the year 2262 after ~95,000 rows, which overflows pandas 2.x nanosecond datetimes (pandas 3 tolerates it). It is now spaced one second apart.
Changed¶
CI: the test workflow runs on every push and pull request (any branch) and on demand, and checks
import tamfirst on every Python version (3.10-3.14).
1.3.0 - 2026-09-06¶
Added¶
Statistics layer (
tam.model.statistics) : a modular “how” beside the structural spectrum “what”, built on the single P-WLS atom (BaseTAM._solve_pwls_step), so the defaultloss="l2"path stays bit-identical to ordinary least squares.Reweighting & estimation (
estimation/): GLM families (Gamma, Poisson, Binomial), asymmetric expectiles, and robust M-estimators (Huber, Student-t) viaStaticTAM(loss=...), driven by an IRLS schedule over the atom.Distributional location-scale fits via a dict formula/loss (
{"mu": ..., "sigma": ...}), with automatic Normal/Student-t tail selection,predict_quantiles,cdf,anomaly_scoreandcrps.Mixture of TAM regressions (
mixture_components=K) fitted by EM whose M-step is the responsibility-weighted atom.Gaussian copula (
GaussianCopulaTAM) binding several distributional margins.Conformal & ACI (
statistics.risk): distribution-free CQR intervals, conformal p-values, Mondrian (stratified) calibration (ConformalDistributionalTAM) and streaming Adaptive Conformal Inference, on the staticSafetyTAMengine.EVT & epistemic uncertainty: Generalized-Pareto tail scoring (
GeneralizedParetoTail,fit_gpd_tail) and Bayesian posterior parameter uncertainty (posterior_prediction).
1.2.6 - 2026-07-17¶
Added¶
Added SPDX license identifiers (
LGPL-3.0-or-later) and standardized file headers with proper authorship and copyright attribution across the entire codebase (2026-07-01).
Changed¶
Major Data Upgrade: Replaced the legacy
dataset_national.csvwith the new FORCE (French Open Research Catalogue of Energy) dataset. The library now defaults to this high-performance, harmonized dataset for baseline benchmarking and examples.
Fixed¶
Critical Tensor Alignment Bug (
group_col): Fixed an order-sensitivity vulnerability in the tensor stacking and DataFrame reassembly layers. The framework now enforces strict chronological sorting (viadate_col) before building 3D tensors, preventing penalty matrix corruption on non-sequential data. Additionally, it now safely maps chronological PyTorch predictions back to shuffled Pandas indices, guaranteeing row-to-row integrity.
1.2.5 - 2026-06-24¶
Added¶
Topological Split Strategies (
TreeEffect): Formalized thesplit_strategyparameter. Users can now explicitly toggle between'uniform'(creating mathematically orthogonal, shift-invariant Cartesian grids) and'quantile'(applying the empirical Probability Integral Transform to create density-adaptive partitions that perfectly balance sample distributions across all leaves).
Changed¶
Empirical Sparsity-Adaptive Penalty (Anisotropic Ridge): Upgraded the structural penalty of the Random Forest (
t(...)) and Linear Tree (lt(...)) modules. By settingsp_alpha > 0, the initialization pass now accurately records the empirical data density of each terminal leaf (\(C_i\)).Drift & Singularity Prevention: Starved or empty edge-boundary leaves now receive geometrically massive penalties. This guarantees global matrix rank, eliminates the catastrophic test drift associated with hard Cartesian grids, and theoretically resolves the OLS singularities traditionally found in Model-Based Recursive Partitioning (MOB).
1.2.4 - 2026-06-22¶
Added¶
API Standardization: Introduced explicit
fit()andpredict()methods across all meta-models (AdaptiveTAM,OperaTAM,KalmanTAM). This establishes a unified, scikit-learn-like operational workflow (train on historical data, freeze state, predict out-of-sample) regardless of the underlying algorithm.AdaptiveTAM: Added
fit()andpredict()methods for production deployment. Thefit()method efficiently extracts and solves the linear system strictly for the final available training window. Thepredict()method then applies this frozen state (last_state_dict_) to new data in \(O(1)\) time with strict safety clipping, ensuring instant, deterministic inference without target leakage.KalmanTAM: Added
fit()andpredict()methods alongside end-of-training state extraction (last_state_dict_andscale_dict_). This allows users to project the finalized Kalman drift weights forward as a stable, static rule on new data, with the internal normalization math handled automatically.OperaTAM: Added
fit()andpredict()methods to transition from continuous dynamic simulation to frozen-weight inference.fit()runs the historical simulation, whilepredict()cleanly extracts and applies the final expert aggregation weights to new out-of-sample data.
Fixed¶
StaticTAM: Removed the
target_colrequirement from the required features check indecompose_prediction. This resolves a critical blocker for operational inference pipelines where the target variable is naturally unavailable.KalmanTAM: Patched
_prepare_kalman_featuresto securely bypass target column extraction during out-of-sample inference, preventing crashes when the target variable is absent.
1.2.3 - 2026-06-08¶
The DOI was generated via Zenodo on release : https://doi.org/10.5281/zenodo.20543272.
✨ Added (New Models & Core Features)¶
Universal Extrapolation Wrapper: Introduced native Out-Of-Distribution (OOD) extrapolation for all base effects via the
extrapolateparameter. It safely bounds the feature map to the \([-1, 1]^F\) hypercube and utilizes multidimensional directional derivatives (stepping strictly backward into the safe zone) for OOD inputs. Supported modes includecontinue(native topology),constant(plateau/clamping),linear(first-order Taylor expansion), andsaturation(smooth asymptotic clamping).Linear Tree (
lt(...)): Added a native effect that generates piecewise linear models. It utilizes a dedicatedLinearTreeEffectclass to encapsulate a standardTreeEffect(acting as the local intercept/level) crossed with aTensorProductEffect(acting as the local linear slope). This provides a single, cohesive model for varying-coefficient trees, seamlessly handling multi-dimensional spatial data without requiring formula macro workarounds.Flat N-ary Histograms (
TreeEffect): Added themax_leavesparameter to bypass binary depth and force flat 1D N-ary splits. This includes an Anti-Starvation Protocol (evenly spaced bins) for single trees to guarantee full matrix rank and prevent over-complete matrix singularities in piecewise regressions.Academic Reproductions: Added official benchmark scripts reproducing foundational load forecasting architectures using the TAM framework:
2011_pierrot_goude.py: Benchmarks native grouping vs. PyGAM manual loops using local B-splines.2025_doumeche_et_al.py: Benchmarks the transition from local splines to global Fourier bases with Sobolev regularization.
Theory, Cheatsheets and Documentation: Added comprehensive TAM documentation:
THEORY as the central mathematical reference and
cheatsheet.pyto showcase the entire TAM spectrum (Static bases, Neural Networks, Physics operators) wrapped in Meta-Learners.The StaticTAM
The Primal Model: Theory | Architecture
Tensorization & Data: Theory | Architecture
Linear Systems: Theory | Architecture
Complexity & Hardware: Theory | Architecture
GCV & Auto-ML: Theory | Architecture
The base effects : Linear / Fourier / Spline / Chebyshev / Categorical / Interaction / RBF / Neural / Tree / Linear Tree / Wavelet / PID / Physics
The AdaptiveTAM
Adaptive Online Learning: Theory | Architecture
The OperaTAM
Expert Aggregation (Opera): Theory | Architecture
🚀 Changed (Major Refactoring & Optimization)¶
OPERA Dual API Support (
OperaTAM): Added a standard array-based initialization (target_col="y",expert_cols=["E1", "E2"]) alongside the existing R-like formula API (formula="y ~ l(E1) + l(E2)"), allowing for simpler dynamic aggregation.Architectural Shape Normalization: Overhauled
build_feature_mapacrossTreeEffect,NeuralEffect, andRBFEffect. Added a dynamic dimensional router to natively resolve tensor broadcasting ambiguities across 1D (OOD wrappers), 2D (Kroneckerte(...)interactions), and 3D+ (Primal Solver Factory) inputs.Formula Parser Robustness: Upgraded
parse_formula_to_termsto explicitly track and uniquely index nested sub-arguments using positional indices (i,j). Resolves parameter collision and overwriting issues when parsing nested interaction terms containing identical effect types.Memory Probe Safeguards (Dummy Pass): Improved robustness of the VRAM footprint estimation during the dummy pass across all base effects. This prevents premature initialization of randomized partition geometries, NEPT weights, or RBF centers during the framework’s memory estimation phase.
Categorical Effect Automation: The Categorical effect (
c(...)) now automatically parses the dataset to countn_catif the parameter is omitted by the user.MLOps Dashboard (
plotting_dashboard):Enhanced chronological forecast plots with a
forecast_smoothingparameter (supports rolling averages and date-based resampling).Implemented dynamic evaluation metrics for the Test Set Vulnerability heatmap (automatically scaling for RMSE, MAE, MAPE, etc.).
Unified color mapping across all subplots ensuring consistent model identification using Matplotlib’s
tab10colormap.
[Internal] 1.2.2 - 2026-03-26 (Not publicly released)¶
✨ Added (New Models & Core Features)¶
Evolutionary Orchestrator (
AutoTAM): A multi-fidelity AutoML engine for automated GAM discovery. It utilizes a Hub-and-Spoke evolutionary architecture, strict topological sanitization, and bi-level optimization (GPU MSP-GCV) to solve the combinatorial explosion of adaptive models, ultimately deploying orthogonal experts into a Dual OPERA arena.OPERA (
OperaTAM): A new expert aggregation meta-learner featuring a fast GPU implementation natively optimized via@torch.jit.script.Kalman Filter (
KalmanTAM): Dynamically tracks coefficient drift over time via a Fast Dynamic Extended Kalman Filter (EKF), highly optimized using the Woodbury matrix identity (reducing inversion complexity to \(\mathcal{O}(T_{block}^3)\)) and compiled withTorchScript.DeepGAM (
NeuralTAM): A new Deep-GAM hybrid model (Additive + Deep Learning) implementing Group-wise Orthogonal Backfitting.Tree Effect (
TreeEffect): Added the Tree / Random Forest effect (t(...)) designed for GPU, based on Oblivious Random Trees and Random Binning Features approximation.Hardware Manager (
HardwareManager): Centralized hardware abstraction layer to dynamically manage the capabilities of different compute backends._dispatcher.py(Mathematical Solver Dispatcher): Created an intelligent routing layer between statistical modeling abstractions and PyTorch linear algebra engines. It dynamically routes resolution to either a chunked direct solver or a Matrix-Free Sparse Conjugate Gradient (CG) solver based on topological complexity and available VRAM._memory.py(Hardware Memory Management and Estimation): Completely isolated low-level hardware interactions into a dedicated module. It estimates the byte footprint of massive matrices and calculates safe algorithmic chunk sizes.
🚀 Changed (Major Refactoring & Optimization)¶
Neural Effect Improvements (
NeuralEffect): Added support for multiple hidden layers to project variables into higher dimensions.Native GPU Acceleration: Complete migration of intensive CPU to GPU calculation for Splines (
s(...)), Wavelets (w(...)), and RBF (rbf(...)) effects, improving performance of design matrix construction.Memory Management (Safeguards & Smart Chunking):
Overhauled memory safety to prevent and correct CUDA Out of Memory bugs via a smart chunking system.
Implemented a memory safeguard for CPU / group-chunking by independent series.
Established strict dynamic RAM & VRAM safety margins to guarantee the stability of large matrix inversion operations.
[Internal] 1.2.1 - 2025-12-18 (Not publicly released)¶
This version represents a complete architectural overhaul, introducing advanced functional bases (Spectrum), Conformal Prediction, and a full benchmark suite.
✨ Added (New Models & Core Features)¶
Auto-ML (GCV): Added
StaticTAM.auto_fit()using Generalized Cross Validation (GCV) for automatic global regularization parameter selection, eliminating the need for a validation set.Safety Module (Conformal Prediction): Added
SafetyTAMimplementing Split Conformal (static) and Adaptive Conformal Inference (ACI) (dynamic) to guarantee valid confidence intervals under distribution shift.Hierarchical Reconciliation: Added
HierarchicalTAMto solve global constraints (e.g., National = Sum of Regions) via joint optimization on the primal system.Model Introspection: Added
StaticTAM.summary()to display the model’s structure, complexity, and regularization parameters.Core Effects Library (
spectrum): Implemented a complete modular library of advanced functional bases:ChebyshevEffect(p(...)): Global polynomials for stable trend approximation.WaveletEffect(w(...)): Ricker wavelets for local anomaly and transient feature detection.NeuralEffect(n(...)): Neural projection for high-dimensional non-linearity.RBFEffect(rbf(...)): Support for both Gaussian and Matérn (physics-informed) kernels.TensorProductEffect(te(...)): Multivariate interactions (Kronecker product) for surface modeling.UniversalPhysicsEffect(phys(...)): PIKL (Physics-Informed Kernel Learning) for constraining models with differential operators (ODEs/PDEs).
🚀 Changed (Major Refactoring & Optimization)¶
Math Engine (Primal Solver): Formally validated the exact Primal Ridge Solver utilizing block-diagonal covariance accumulation. Corrected performance tracking to accurately reflect the framework’s time complexity of \(\mathcal{O}(G \times T \times D^2 + G \times D^3)\), ensuring isolated mathematical resolution per group \(G\).
Effect Architecture: Refactored the core around
BaseEffect, establishing theList[BaseEffect]as the standard configuration.Modularization: Monolithic
_effects.pywas entirely split into thespectrumpackage, improving modularity.Normalization Domain: Changed global feature normalization from the Fourier-centric \([-\pi, \pi]\) to the strictly orthogonal \([-1, 1]\) domain in
_data.py. Basis functions now apply internal scaling (e.g., Fourier rescales to \([-\pi, \pi]\)).Decomposition Robustness: Implemented collision detection in
_math.pyto automatically prefix feature effects (e.g.,l_time,s_time) when multiple bases share the same input variable.
🐛 Fixed (Critical)¶
Recursive Parsing: Implemented an architectural fix in
parse_formula_to_termsto correctly identify and preserve string tokens (likega_teorgrid_k) during the recursive parsing ofte(...)terms.Syntax Stability: Converted all docstrings containing LaTeX math commands to raw strings (
r"""...""") to eliminate PythonSyntaxWarnings.
[Internal] 1.1.1 - 2025-11-21 (Not publicly released)¶
This version introduced the Formula API and the first object-oriented refactoring.
⚠️ Breaking Changes¶
Removed legacy dictionary-based API (
m_orders,s_orders,alpha_list)Introduced formula-based API as the primary interface
✨ Added¶
Formula-based API (
model/additive.py): Implemented a new, intuitive R-like formula API (e.g.,Load ~ s(temp, k=10) + l(day_type)) as the new standard for model initialization.Spline Effects (
model/_effects.py): AddedSplineEffect(P-splines) as a new core effect type, available vias(...).Formula Parser (
common/utils.py): Added aparse_formula_to_termsfunction to support the new API.StaticTAM&AdaptiveTAM: Implemented the full object-oriented API (.fit(),.predict()) and the online error correction model.Multi-Start Grid Search: The
grid_search_fitmethod now uses a Multi-Start Coordinate Descent strategy (Conservative, Median, Aggressive) to avoid local minima.diagnosticsModule: Added a module for model analysis, including t-tests and feature importance visualization.
⚙️ Changed¶
Legacy API Removed: Removed the old
m_orders,s_orders,alpha_listdictionary-based configuration fromv0.0.6.Package Structure: The codebase was refactored into a modular package structure (
common,model).Internal Math: Math functions (
_math.py) were cleaned of all effect-specific logic and made robust to 2D/3D tensor inputs.Hardcoded Names Removed: Removed dependencies on specific column names (
tod,timestamp,Load).
0.0.6 - 2025-05-27¶
Added¶
Initial project setup based on the original
weaklv0.0.6 package.