Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

premdev1234
Copy link

Entropy-Based Pruning in Trinomial Tree Lattices for Efficient Hull-White Pricing

Author: Prem Dev
Date: July 2, 2025


Abstract

In affiliation to issue #364

This document proposes an enhancement to QuantLib's TrinomialTree class to improve computational efficiency when the time discretization step is very small—a common scenario in pricing interest rate derivatives like Bermudan swaptions under the Hull-White model. The patch introduces entropy-based pruning to suppress unnecessary branching in nearly deterministic transitions. Benchmarks show an 8.6% increase in throughput without any test regressions.


1. Context and Motivation

The Hull-White one-factor model assumes the short rate $r_t$ evolves as an Ornstein-Uhlenbeck process:

$$ dr_t = (\theta(t) - a r_t) dt + \sigma dW_t $$

Where:

  • $a$: mean-reversion rate
  • $\sigma$: volatility
  • $\theta(t)$: ensures fit to initial term structure

For small $\Delta t$:

$$ \mathbb{E}[r_{t+\Delta t}] = r_t e^{-a \Delta t} + \frac{\theta(t)}{a}(1 - e^{-a \Delta t}) $$

$$ \text{Var}[r_{t+\Delta t}] = \frac{\sigma^2}{2a} (1 - e^{-2a \Delta t}) $$

As $\Delta t \to 0$, variance collapses. However, QuantLib’s tree expands nodes based on high branching even when the process becomes deterministic.


2. Observed Issue in QuantLib

The state spacing in TrinomialTree is:

$$ \Delta x_i = \sqrt{3 \cdot \text{Var}_i} $$

Node index is:

$$ \texttt{temp} = \left\lfloor \frac{\mathbb{E}[r_{t+\Delta t}] - x_0}{\Delta x_{i+1}} + 0.5 \right\rfloor $$

Problems when $\Delta t$ is small:

  • $\Delta x \to 0$
  • temp becomes large
  • Creates many unused nodes
  • Correct but inefficient

3. Proposed Fix: Entropy-Based Pruning

We compute Shannon entropy:

$$ H = -\sum_{i=1}^{3} p_i \log(p_i) $$

Pruning Criteria

if (v2 < 1e-12) {
    branching.add(temp, 0.0, 1.0, 0.0);
    continue;
}

Real H = entropy(p1, p2, p3);
if (H < 1e-3 && std::max(p1, p3) < 1e-12) {
    p1 = 0.0; p2 = 1.0; p3 = 0.0;
}
branching.add(temp, p1, p2, p3);

Interpretation

  • If transition is deterministic, enforce a single middle-node jump
  • Eliminates noise from low-probability branching

4. Empirical Results

Metric Before After Improvement
System Throughput 0.68695 0.74589 +8.6%
Total Runtime 379.94 s 349.91 s −30.03 s
Unit Tests Passed ✅ 1135/1135 ✅ 1135/1135 No regressions
Valgrind Check Clean

5. Validation Logs


6. Conclusion

This patch addresses over-branching in TrinomialTree construction under small time steps—critical in Hull-White-based lattice models. The entropy-based pruning is:

  • Mathematically sound
  • Lightweight
  • Backward-safe

Copy link

boring-cyborg bot commented Jul 2, 2025

Thanks for opening this pull request! It might take a while before we look at it, so don't worry if there seems to be no feedback. We'll get to it.

@coveralls
Copy link

Coverage Status

coverage: 73.819% (+0.003%) from 73.816%
when pulling 16e654f on premdev1234:master
into 01fe85d on lballabio:master.

@lballabio
Copy link
Owner

lballabio commented Aug 1, 2025

Thanks for the contribution—I don't think it addresses the main issue, though.

When there's a very small step, we have a situation like this:

before

Small step from t1 to t2, large step from t2 to t3. They're not to scale: usually the small step is smaller.

Because of the small step and therefore the small variance, the dx at t2 is also small and we have a lot of nodes (again, not to scale; they would be many more than this). Each of the nodes at t1 reaches out to three of them, but because there are so many of them not all of them are reached. The blue nodes are reached, the red nodes are not.

The dx at t3 is large (because of the large step) and again we have fewer nodes. Each of the nodes at t2 reaches out to three of them.

When doing the rollback from t3 to t2, we're recombining three nodes at t3 for each of the nodes at t2. There's a lot of nodes at t2, and so this is a lot of work; and we're doing it for all nodes at t2, both blue and red.

When doing the rollback from t2 to t1, we're recombining three blue nodes at t2 for each of the nodes at t1. The red nodes are not used; the work made for them at the previous step is thrown away.

Now, as far as I can see (correct me if I'm wrong) your pull request turns the picture above into this:

after

that is, when the variance is small, we're just going to the mid node with probability 1 and setting 0 for the other two probabilities. The compiler is probably optimizing this in some way and giving you the throughput increase you see. But all the nodes at t2 are still there, and all the work rolling back from t3 to t2 is still done and thrown away for the red nodes.
The real saving would be in avoiding that work somehow.

@CLAassistant
Copy link

CLAassistant commented Aug 4, 2025

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants