Extrusion & Slicing¶
Motivation -- Portfolio Combination¶
In practice, trades depend on different subsets of risk factors. Trade A might depend on (spot, rate) while Trade B depends on (spot, vol). The v0.7.0 algebra operators require operands on the same grid, so these two proxies cannot be added directly.
Extrusion solves this by adding new dimensions where the function is
constant. After extruding both trades to a common 3D grid (spot, rate, vol),
they can be combined with the standard +, -, *, / operators:
Slicing is the inverse: it fixes a dimension at a specific value, reducing dimensionality via barycentric interpolation. Together, extrusion and slicing form the bridge between Chebyshev proxies on heterogeneous risk-factor sets.
When to use extrude/slice
Use extrusion when you need to combine Chebyshev interpolants that live on different sets of dimensions. Use slicing to project a high-dimensional interpolant onto a lower-dimensional subspace (e.g., fixing a parameter at its current market value).
Mathematical Basis¶
Partition of Unity¶
The barycentric basis functions satisfy a fundamental identity:
for all \(x\) in the domain. This is because any polynomial interpolation scheme reproduces constant functions exactly -- the constant \(1\) is interpolated by \(\sum_j 1 \cdot \ell_j(x) = 1\).
Reference
Berrut & Trefethen (2004), "Barycentric Lagrange Interpolation", SIAM Review 46(3):501--517, Section 2.
Extrusion Proof¶
Given a \(d\)-dimensional CT with values \(v_{i_1,\ldots,i_d}\), the extruded \((d+1)\)-dimensional CT inserts a new axis at position \(k\) with \(M\) Chebyshev nodes, replicating values:
Evaluating at any point \((x_1,\ldots,x_{k-1},x^*,x_k,\ldots,x_d)\):
Since the values don't depend on \(j\), the \(j\)-sum factors out:
Result: The extruded CT evaluates to the same value as the original, regardless of the new coordinate. Extrusion is exact.
Slicing Proof¶
Given a \(d\)-dimensional CT, fixing dimension \(k\) at value \(x^*\):
Factoring out the \(k\)-th dimension:
The contracted values \(\hat{v}\) define a valid \((d-1)\)-dimensional CT.
Fast path: When \(x^*\) coincides with a Chebyshev node \(x_m^{(k)}\)
(within tolerance \(10^{-14}\)), the basis function simplifies to
\(\ell_{i_k}^{(k)}(x_m) = \delta_{i_k,m}\), so
\(\hat{v} = v_{\ldots,m,\ldots}\) -- a simple np.take (no arithmetic
needed).
Extrude-then-Slice = Identity¶
If we extrude along dimension \(k\) and then slice at any value \(x^*\) along \(k\):
Proof. Extrusion replicates values along \(k\), then slicing contracts via \(\sum_j v \cdot \ell_j(x^*) = v \cdot 1 = v\).
Error Bounds¶
- Extrusion: No approximation error introduced (exact operation), following directly from the partition of unity (Berrut & Trefethen 2004).
- Slicing: The sliced CT evaluates the polynomial interpolant at \(x_k = x^*\). No additional error beyond the original approximation error (Trefethen 2013, Ch. 8): if \(\|f - p\|_\infty \leq \epsilon\), then \(\|f(\cdot, x^*) - p(\cdot, x^*)\|_\infty \leq \epsilon\).
Book reference
Extrusion and slicing of Chebyshev Tensors is described in Section 24.2.1, Listing 24.15 (slice) and Listing 24.16 (extrude) of Ruiz & Zeron (2021), Machine Learning for Risk Calculations, Wiley Finance.
Quick Start¶
import math
from pychebyshev import ChebyshevApproximation
def f(x, _): return math.sin(x[0]) + x[1]
def g(x, _): return math.cos(x[0]) * x[1]
# Trade A depends on (spot, rate)
trade_a = ChebyshevApproximation(f, 2, [[80, 120], [0.01, 0.08]], [11, 11])
trade_a.build()
# Trade B depends on (spot, vol)
trade_b = ChebyshevApproximation(g, 2, [[80, 120], [0.15, 0.35]], [11, 11])
trade_b.build()
# Extrude both to 3D: (spot, rate, vol)
trade_a_3d = trade_a.extrude((2, (0.15, 0.35), 11)) # add vol dim
trade_b_3d = trade_b.extrude((1, (0.01, 0.08), 11)) # add rate dim
# Combine into portfolio
portfolio = trade_a_3d + trade_b_3d
price = portfolio.vectorized_eval([100.0, 0.05, 0.25], [0, 0, 0])
Supported Operations¶
| Class | extrude() |
slice() |
|---|---|---|
ChebyshevApproximation |
Yes | Yes |
ChebyshevSpline |
Yes | Yes |
ChebyshevSlider |
Yes | Yes |
ChebyshevTT |
No | No |
Extrude API¶
Parameters
| Parameter | Type | Description |
|---|---|---|
params |
tuple or list of tuples | (dim_index, (lo, hi), n_nodes) |
dim_index-- position in the output space (0 = prepend,d= append)(lo, hi)-- domain bounds for the new dimensionn_nodes-- number of Chebyshev nodes (must match other CTs for later algebra)
Returns: A new interpolant of the same type, already built, with
function=None.
Errors:
RuntimeErrorif the interpolant has not been builtValueErrorifdim_indexis out of range, duplicated,lo >= hi, orn_nodes < 2
Multi-extrude: 1D to 3D
Slice API¶
Parameters
| Parameter | Type | Description |
|---|---|---|
params |
tuple or list of tuples | (dim_index, value) |
dim_index-- dimension to fix (0-indexed in the current object)value-- point at which to fix (must be within the domain)
Returns: A new interpolant of the same type, already built, with
function=None.
Errors:
RuntimeErrorif the interpolant has not been builtValueErrorifvalueis outside the domain,dim_indexis out of range, duplicated, or if slicing all dimensions
Slice 3D to 1D
Fast path at exact nodes
When the slice value coincides with a Chebyshev node (within \(10^{-14}\)),
the contraction reduces to np.take -- a simple array index with no
floating-point arithmetic.
Compatibility with Algebra¶
Extrusion is the key enabler for the v0.7.0 algebra operators. After extruding two CTs to a common grid, all standard operators work:
# Different risk factors
ct_a = ChebyshevApproximation(f, 2, [[80, 120], [0.01, 0.08]], [11, 11])
ct_b = ChebyshevApproximation(g, 2, [[80, 120], [0.15, 0.35]], [11, 11])
ct_a.build(); ct_b.build()
# Extrude to common 3D: (spot, rate, vol)
ct_a_3d = ct_a.extrude((2, (0.15, 0.35), 11))
ct_b_3d = ct_b.extrude((1, (0.01, 0.08), 11))
# Now all algebra operators work
portfolio = 0.6 * ct_a_3d + 0.4 * ct_b_3d
hedged = ct_a_3d - ct_b_3d
scaled = 2.0 * ct_a_3d
The compatibility requirements from Chebyshev Algebra apply to the extruded results: same domain, node counts, derivative order, and number of dimensions.
Derivatives¶
Extrusion: Derivatives in the original dimensions are preserved. Derivatives with respect to the new dimension are zero (the function is constant along the new axis). This follows from \(\mathcal{D}_k \cdot [c, c, \ldots, c]^T = \mathbf{0}\).
Slicing: Derivatives in the remaining dimensions are preserved. The sliced CT has valid spectral differentiation matrices for all surviving dimensions.
# Extrude: derivative w.r.t. new dim is zero
ct_3d = ct_2d.extrude((2, (0.0, 1.0), 11))
assert abs(ct_3d.vectorized_eval([0.5, 0.3, 0.7], [0, 0, 1])) < 1e-12
# Slice: derivative in remaining dim preserved
ct_1d = ct_2d.slice((1, 0.5))
d_dx = ct_1d.vectorized_eval([0.3], [1]) # first derivative w.r.t. dim 0
Serialization¶
Extruded and sliced interpolants support save() and load() just like
any other built interpolant:
ct_3d = ct_2d.extrude((2, (0.0, 1.0), 11))
ct_3d.save("extruded.pkl")
loaded = ChebyshevApproximation.load("extruded.pkl")
loaded.vectorized_eval([0.5, 0.3, 0.7], [0, 0, 0]) # works identically
Class-Specific Notes¶
ChebyshevSpline¶
When extruding a spline, each piece is extruded independently. The new
dimension gets knots=[] (no interior knots) and a single interval.
When slicing a spline, only the pieces whose interval along the sliced
dimension contains the slice value survive. Each surviving piece is then
sliced via its underlying ChebyshevApproximation.slice().
ChebyshevSlider¶
When extruding a slider, the new dimension becomes its own single-dim
slide group with tensor_values = np.full(n, pivot_value), so the slide
contributes zero: \(s_{\text{new}}(x) - pv = 0\) for all \(x\). The
partition indices for existing dimensions are remapped accordingly.
When slicing a slider, two cases arise:
- Multi-dim group: The slide's
ChebyshevApproximationis sliced at the local dimension index within the group. - Single-dim group: The slide is evaluated at the slice value, giving
a constant \(s_{g^*}(v)\). The shift \(\delta = s_{g^*}(v) - pv\) is
absorbed into
pivot_valueand each remaining slide's tensor values.
Limitations¶
- No
ChebyshevTTsupport -- extrusion and slicing for Tensor Train interpolants are not currently implemented. - Operand must be built --
build()must have been called before callingextrude()orslice(). - No cross-type operations -- you cannot extrude a
ChebyshevSplineand then add it to aChebyshevApproximation. - Result has
function=None-- the extruded/sliced interpolant cannot callbuild()again, since it has no underlying function reference.
References¶
- Berrut, J.-P. & Trefethen, L. N. (2004). "Barycentric Lagrange Interpolation." SIAM Review 46(3):501--517.
- Ruiz, G. & Zeron, M. (2021). Machine Learning for Risk Calculations. Wiley Finance. Section 24.2.1.
- Trefethen, L. N. (2013). Approximation Theory and Approximation Practice. SIAM. Chapter 8.