Reconciliation tools
This module provides utility classes for forecast reconciliation, with support for both cross-sectional and temporal frameworks. The tools in FoRecoPy are built around structured matrices that represent aggregation relationships and linear constraints, which serve as the foundation for different reconciliation methods. Two complementary toolsets are available:
cstools()
: For hierarchically, grouped, or otherwise linearly constrained series observed at the same frequency.tetools()
: For temporal hierarchies, where the same time series can be aggregated or linearly combined at multiple frequencies (e.g., monthly, quarterly, yearly). This allows one to reconcile forecasts across frequencies so that, for example, the sum of 12 monthly forecasts matches the corresponding annual forecast.
- class cstools(agg_mat: Array = None, cons_mat: Array = None)[source]
Cross-sectional reconciliation tools
Utilities for working with linearly constrained (hierarchical/grouped) multivariate time series in a cross-sectional framework.
This class encapsulates standard matrices used in forecast reconciliation: the aggregation matrix \(\mathbf{A}\), the structural matrix \(\mathbf{S}\), and the zero-constraints matrix \(\mathbf{C}\). Given either \(\mathbf{A}\) or \(\mathbf{C}\) at construction, the remaining matrices and dimension metadata are derived.
Parameters
agg_mat
: ndarrayA (\(n_a \times n_b\)) numeric matrix representing the cross-sectional aggregation matrix. It maps the \(n_b\) bottom-level (free) variables into the \(n_a\) upper (constrained) variables.
cons_mat
: ndarrayA (\(n_a \times n\)) numeric matrix representing the cross-sectional zero constraints. It spans the null space for the reconciled forecasts.
Attributes
agg_mat
: ndarrayThe aggregation matrix \(\mathbf{A}\) (may be inferred from \(\mathbf{C}\)).
dim
: tupleDimension summary:
if \(\mathbf{A}\) given: \((n, n_a, n_b)\) with \(n = n_a + n_b\).
if \(\mathbf{C}\) given: \((n, r, n - r)\) with \(r = \text{ rank/rows of } \mathbf{C}\).
_cons_mat
: ndarrayThe constraints matrix \(\mathbf{C}\), built on demand if \(\mathbf{A}\) is provided.
_strc_mat
: ndarrayThe structural matrix \(\mathbf{S} = [\mathbf{A}'\quad\mathbf{I}_{n_b}]'\).
Methods
strc_mat()
-> jnp.ndarrayReturns the temporal structural matrix \(\mathbf{S}\). Requires agg_mat to be available.
cons_mat()
-> jnp.ndarrayReturns the temporal constraints matrix \(\mathbf{C}\).
Notes
Shapes:
\(\mathbf{A}\) has shape \((n_a, n_b)\).
\(\mathbf{S}\) has shape \((n_a + n_b, n_b) = (n, n_b)\).
\(\mathbf{C}\) has shape \((n_a, n) = (n_a, n_a + n_b)\) when built from \(\mathbf{A}\).
When initialized with cons_mat, \(\mathbf{A}\) is only inferred if the leading \((r\times r)\) block equals the identity; specifically, if \(\mathbf{C} = [\mathbf{I}_{r}\quad-\mathbf{A}]\).
See Also
Examples
>>> import jax.numpy as jnp >>> import forecopy as rpy >>> # One-level hierarchy: Z = X + Y >>> A = jnp.array([[1., 1.]]) # shape (n_a=1, n_b=2) >>> tools = rpy.cstools(agg_mat=A) >>> tools.dim (3, 1, 2) >>> S = tools.strc_mat() >>> S.shape # [A' ; I_2]' (3, 2) >>> C = tools.cons_mat() >>> C # [I_1 -A] Array([[ 1., -1., -1.]], dtype=float32) >>> >>> # Start from constraints: C = [1, -1, -1] >>> C = jnp.array([[1., -1., -1.]]) # r=1, n=3 >>> tools2 = rpy.cstools(cons_mat=C) >>> tools2.dim (3, 1, 2) >>> tools2.agg_mat # inferred because C = [I | -A] Array([[1., 1.]], dtype=float32) >>> tools2.strc_mat().shape (3, 2)
- class tetools(agg_order: list | int, tew: str = 'sum', fh: int = 1)[source]
Temporal reconciliation tools
Utilities for forecast reconciliation through temporal hierarchies.
Given a set of temporal aggregation orders, this class constructs the temporal aggregation matrix (linear-combination matrix) and provides the corresponding structural and zero-constraint matrices used in temporal reconciliation.
Parameters
agg_order
: list | intHighest available sampling frequency per seasonal cycle (max. order of temporal aggregation, \(m\)), or a list representing a subset of \(p\) factors of \(m\).
tew
: str, default sumTemporal aggregation weighting scheme applied within each high-to-low block when building the aggregation matrix:
sum: sum over the block.
avg: arithmetic average over the block.
last: take the last element in the block.
first: take the first element in the block.
fh
: int, default 1Forecast horizon for the lowest frequency (most temporally aggregated) series.
Attributes
m
: intMaximum aggregation order, m = max(agg_order).
kset
: list[int]Decreasing set of temporal aggregation orders that divide m. If a single integer was supplied to agg_order, this equals the full list of positive factors of m.
p
: intNumber of elements in kset.
ks
: intPartial sum of factors \(k^\ast\), defined as sum(m / kset[:-1]).
kt
: intTotal sum of factors \(k_t\), defined as sum(m / kset).
tew
: strThe requested temporal weighting flag (see parameter description).
_agg_mat
: jnp.ndarrayTemporal aggregation matrix \(\mathbf{A}\).
_strc_mat
: jnp.ndarray or NoneTemporal structural matrix, \(\mathbf{S} = [\mathbf{A}'\quad\mathbf{I}_{m}]'\).
_cons_mat
: jnp.ndarray or NoneTemporal zero-constraints matrix, \(\mathbf{C} = [\mathbf{I}_{k^\ast}\quad-\mathbf{A}]\).
Methods
strc_mat()
-> jnp.ndarrayReturn the temporal structural matrix \(\mathbf{S}\).
cons_mat()
-> jnp.ndarrayReturn the temporal constraints matrix \(\mathbf{C}`\).
Notes
- Shapes:
\(\mathbf{A}\) has shape \((k^\ast, m)\).
\(\mathbf{S}\) has shape \((k^\ast + m, m) = (k_t, m)\).
\(\mathbf{C}\) has shape \((k^\ast, k_t)\).
See Also
Examples
>>> import jax.numpy as jnp >>> import forecopy as rpy >>> >>> # Quarterly over monthly (m = 4), full factor set {4,2,1} >>> obj = rpy.tetools(agg_order=4, tew='sum', fh=1) >>> obj.kset [4, 2, 1] >>> A = obj._agg_mat >>> S = obj.strc_mat() >>> C = obj.cons_mat() >>> A.shape, S.shape, C.shape ((3, 4), (7, 4), (3, 7)) >>> >>> # Custom set (divisors of m=12 that you care about): {12, 6, 3, 1} >>> obj2 = rpy.tetools(agg_order=[12, 6, 3, 1], fh=2) >>> obj2.kset [12, 6, 3, 1] >>> obj2._agg_mat.shape # i.e., (2+4+24, 12) = (30, 12) ( (12/6)*2 + (12/3)*2 + (12/1)*2, 12 )