Skip to content

The Nelson-Siegel curve, live

The yield at a tenor from the curve's three factors, y(t) = b₀ + b₁ L + b₂ (L − e⁻ˣ), with x = t / τ and the slope's loading L = (1 − e⁻ˣ) / x: the long end tends to the level b₀, the short end to the level plus the slope b₁, and the curvature b₂ bends the middle (lusine.finance.nelson_siegel). Below x = ½, where 1 − e⁻ˣ in binary32 would lose the loading's digits, L is its series. Below, three curves with τ = 1.5 years, a normal one rising, an inverted one falling and a humped one, are swept on your GPU as you read from a twentieth of a year to thirty years, a tenth of a year a step; each is held at sixty-one tenors to the law in float64; and a fourth is taken across the series' seam.

This page runs the program on your GPU through WebGPU, so it needs a browser with WebGPU (a recent Chrome, Edge, Safari or Firefox). Without it the program does not run and nothing is drawn below.

What it shows

  • The strip above the controls is green while every check holds, and turns red for good once one fails.
  • The curves: the chart draws the three curves' yields in percent against the tenor, a point a step. Below it, the tenor and the three yields.
  • The checks: the law in float64, each curve at each of its sixty-one tenors within 4 binary32 epsilons (2⁻²³) of its factors' sizes added, |b₀| + |b₁| + |b₂|, of the law in float64 with the loading by numpy's expm1; normal, inverted and humped, the normal curve rising at every step, the inverted one falling, and the humped one's peak inside the tenors; the short end and the long, at no tenor and at 10⁻⁸ years the level plus the slope, and at 100 000 years the level with the slope's and the curvature's loadings both τ / t, each within 2 epsilons of the level; across the series' seam, at thirteen tenors from x = 0.1 to 2, seven of them within four roundings of x = ½, the curve within 4 epsilons of the law, and its seven yields at the seam within 4 epsilons of each other; linear in its factors, every factor doubled doubling the yield, bit for bit. Each is held at every step.

Every number here is computed by the program on the GPU; the page only reads the values back and draws them. τ, the curves' factors and the ends' tenors are the program's settings, which the host may write; this page offers no control to change them yet.

The program

The points, the seam's tenors, the sweep and the checks, the panels the page draws, and the one procedure, main, run each step: the yields at the points and across the seam, the tenor a tenth of a year on and the curves there, and the checks.

// The Nelson-Siegel curve's live page: a normal, an inverted and a humped curve swept from a twentieth of a year to
// thirty years, each held at sixty-one tenors to the law in float64; the series' seam crossed a few roundings at a
// time; the short end and the long; and the factors doubled, with the page's checks computed here on the GPU and shown
// by the panels the program declares.

namespace nelson_siegel;

lusine.version version = { { number = 1 } };

// The reader's settings: the decay's scale, tau, and the three curves' factors, the level, the slope and the curvature;
// the seam's curve's; and the short and the long ends, nothing, 1e-8 years and 100 000 years. Each rate is held a
// second and each time in seconds, as the device stores them.
host struct {
  float<s> tau = 1.5 year;
  float<s^-1> normal_level = 0.045 year^-1; float<s^-1> normal_slope = -0.02 year^-1;
  float<s^-1> normal_curvature = 0.0 year^-1;
  float<s^-1> inverted_level = 0.03 year^-1; float<s^-1> inverted_slope = 0.02 year^-1;
  float<s^-1> inverted_curvature = 0.0 year^-1;
  float<s^-1> humped_level = 0.04 year^-1; float<s^-1> humped_slope = -0.01 year^-1;
  float<s^-1> humped_curvature = 0.04 year^-1;
  float<s^-1> level = 0.04 year^-1; float<s^-1> slope = -0.015 year^-1; float<s^-1> curvature = 0.02 year^-1;
  float<s> nothing = 0.0 year; float<s> short = 0.00000001 year; float<s> long = 100000.0 year;
} settings;

// The three curves at sixty-one tenors from a twentieth of a year to thirty years, shape 0 the normal, 1 the inverted
// and 2 the humped: each the law in float64, the loading by numpy's expm1, as two binary32 numbers a second, its
// rounding and the rest; the kernel's yield, and whether it is within 4 binary32 epsilons (2^-23) of the curve's
// largest factor's size, the three added.
struct point {
  integer shape; float<s> tenor; float<s^-1> reference; float<s^-1> low; float<s^-1> yld; bool holds;
};
host table<point> points(capacity = 183) = {
  { shape = 0, tenor = 0.05 year, reference = 8.026485032175401e-10 s^-1,
    low = -3.673736575016448e-18 s^-1 },
  { shape = 0, tenor = 0.5491666666666667 year, reference = 8.952643071324928e-10 s^-1,
    low = 3.181632352947932e-18 s^-1 },
  { shape = 0, tenor = 1.0483333333333333 year, reference = 9.69961444496903e-10 s^-1,
    low = -2.406472384655813e-17 s^-1 },
  { shape = 0, tenor = 1.5475 year, reference = 1.0306026032580462e-09 s^-1,
    low = -5.33759697684094e-17 s^-1 },
  { shape = 0, tenor = 2.0466666666666664 year, reference = 1.0801666228132945e-09 s^-1,
    low = -4.72042726477553e-17 s^-1 },
  { shape = 0, tenor = 2.545833333333333 year, reference = 1.1209585482063744e-09 s^-1,
    low = 4.450277355905102e-17 s^-1 },
  { shape = 0, tenor = 3.045 year, reference = 1.1547687250867966e-09 s^-1,
    low = -7.80794970779014e-18 s^-1 },
  { shape = 0, tenor = 3.5441666666666665 year, reference = 1.1829923707296075e-09 s^-1,
    low = 1.3043576160054728e-17 s^-1 },
  { shape = 0, tenor = 4.043333333333333 year, reference = 1.2067217225464333e-09 s^-1,
    low = -5.325259081696344e-17 s^-1 },
  { shape = 0, tenor = 4.5424999999999995 year, reference = 1.2268147608907043e-09 s^-1,
    low = 1.8793121655092387e-17 s^-1 },
  { shape = 0, tenor = 5.041666666666666 year, reference = 1.2439490548743493e-09 s^-1,
    low = -9.511978992776942e-18 s^-1 },
  { shape = 0, tenor = 5.540833333333333 year, reference = 1.2586613973297744e-09 s^-1,
    low = 4.407446936403841e-17 s^-1 },
  { shape = 0, tenor = 6.04 year, reference = 1.2713796682106704e-09 s^-1,
    low = -1.8092448391061994e-17 s^-1 },
  { shape = 0, tenor = 6.539166666666667 year, reference = 1.282445927230924e-09 s^-1,
    low = 1.1849966116669285e-17 s^-1 },
  { shape = 0, tenor = 7.038333333333333 year, reference = 1.292135620722945e-09 s^-1,
    low = -5.1461317965590056e-17 s^-1 },
  { shape = 0, tenor = 7.5375 year, reference = 1.3006710153362633e-09 s^-1,
    low = 1.3691655626377774e-17 s^-1 },
  { shape = 0, tenor = 8.036666666666667 year, reference = 1.3082330774238926e-09 s^-1,
    low = -2.2874592097648473e-18 s^-1 },
  { shape = 0, tenor = 8.535833333333334 year, reference = 1.3149693556258057e-09 s^-1,
    low = -3.0604924967020925e-17 s^-1 },
  { shape = 0, tenor = 9.035 year, reference = 1.3210009752739893e-09 s^-1,
    low = -9.0612747467764e-18 s^-1 },
  { shape = 0, tenor = 9.534166666666668 year, reference = 1.326427967462962e-09 s^-1,
    low = 4.651863918162235e-17 s^-1 },
  { shape = 0, tenor = 10.033333333333333 year, reference = 1.3313334878972682e-09 s^-1,
    low = -4.153227202642204e-17 s^-1 },
  { shape = 0, tenor = 10.5325 year, reference = 1.3357864814267373e-09 s^-1,
    low = -1.2900222451176838e-17 s^-1 },
  { shape = 0, tenor = 11.031666666666666 year, reference = 1.3398451237378595e-09 s^-1,
    low = -2.3991002201644955e-17 s^-1 },
  { shape = 0, tenor = 11.530833333333334 year, reference = 1.3435582646437183e-09 s^-1,
    low = -3.290242904455431e-17 s^-1 },
  { shape = 0, tenor = 12.030000000000001 year, reference = 1.3469673154631323e-09 s^-1,
    low = -4.247589650816538e-17 s^-1 },
  { shape = 0, tenor = 12.529166666666667 year, reference = 1.350107470265982e-09 s^-1,
    low = -2.5076493121524817e-18 s^-1 },
  { shape = 0, tenor = 13.028333333333334 year, reference = 1.3530089271185375e-09 s^-1,
    low = 3.154060189743886e-17 s^-1 },
  { shape = 0, tenor = 13.5275 year, reference = 1.3556976652395747e-09 s^-1,
    low = -1.9063447587997166e-17 s^-1 },
  { shape = 0, tenor = 14.026666666666667 year, reference = 1.3581958890895862e-09 s^-1,
    low = -2.08710986154991e-18 s^-1 },
  { shape = 0, tenor = 14.525833333333333 year, reference = 1.360523027571503e-09 s^-1,
    low = 3.625048889597699e-17 s^-1 },
  { shape = 0, tenor = 15.025 year, reference = 1.3626960670976018e-09 s^-1,
    low = -1.4878568815523988e-17 s^-1 },
  { shape = 0, tenor = 15.524166666666666 year, reference = 1.3647295515895053e-09 s^-1,
    low = 5.334730630582321e-17 s^-1 },
  { shape = 0, tenor = 16.023333333333333 year, reference = 1.3666366927012064e-09 s^-1,
    low = -2.323039143042897e-17 s^-1 },
  { shape = 0, tenor = 16.5225 year, reference = 1.3684287036852538e-09 s^-1,
    low = -5.2005831110499013e-17 s^-1 },
  { shape = 0, tenor = 17.02166666666667 year, reference = 1.3701156875711717e-09 s^-1,
    low = -5.206350214280621e-17 s^-1 },
  { shape = 0, tenor = 17.520833333333332 year, reference = 1.3717065261431571e-09 s^-1,
    low = 4.074691366563969e-17 s^-1 },
  { shape = 0, tenor = 18.02 year, reference = 1.3732094350515922e-09 s^-1,
    low = -2.6751758855071312e-17 s^-1 },
  { shape = 0, tenor = 18.519166666666667 year, reference = 1.3746312976792296e-09 s^-1,
    low = -2.8530117762721517e-17 s^-1 },
  { shape = 0, tenor = 19.018333333333334 year, reference = 1.3759785533196123e-09 s^-1,
    low = -3.7075558543606785e-17 s^-1 },
  { shape = 0, tenor = 19.5175 year, reference = 1.3772568641101657e-09 s^-1,
    low = 3.592425547983098e-18 s^-1 },
  { shape = 0, tenor = 20.016666666666666 year, reference = 1.3784714480991056e-09 s^-1,
    low = 2.500884629103023e-17 s^-1 },
  { shape = 0, tenor = 20.515833333333333 year, reference = 1.3796269682231355e-09 s^-1,
    low = 1.3939464048647636e-17 s^-1 },
  { shape = 0, tenor = 21.015 year, reference = 1.3807276433297488e-09 s^-1,
    low = -3.9630861730848447e-17 s^-1 },
  { shape = 0, tenor = 21.514166666666668 year, reference = 1.381777137154927e-09 s^-1,
    low = 1.9418700154392765e-17 s^-1 },
  { shape = 0, tenor = 22.013333333333332 year, reference = 1.3827791134346512e-09 s^-1,
    low = 2.7283022220928395e-19 s^-1 },
  { shape = 0, tenor = 22.5125 year, reference = 1.3837366807933904e-09 s^-1,
    low = -4.047937367703799e-17 s^-1 },
  { shape = 0, tenor = 23.011666666666667 year, reference = 1.3846526147887062e-09 s^-1,
    low = 1.2398536582482815e-17 s^-1 },
  { shape = 0, tenor = 23.510833333333334 year, reference = 1.38552969097816e-09 s^-1,
    low = 2.879442512948936e-17 s^-1 },
  { shape = 0, tenor = 24.01 year, reference = 1.3863703518524062e-09 s^-1,
    low = -8.224059606212491e-18 s^-1 },
  { shape = 0, tenor = 24.509166666666665 year, reference = 1.3871767068351915e-09 s^-1,
    low = 1.9952365652748702e-17 s^-1 },
  { shape = 0, tenor = 25.008333333333333 year, reference = 1.3879508653502626e-09 s^-1,
    low = 5.409978920034025e-17 s^-1 },
  { shape = 0, tenor = 25.5075 year, reference = 1.3886948257990639e-09 s^-1,
    low = -1.4430865580785788e-17 s^-1 },
  { shape = 0, tenor = 26.006666666666668 year, reference = 1.3894101424938299e-09 s^-1,
    low = 4.740673006576133e-18 s^-1 },
  { shape = 0, tenor = 26.50583333333333 year, reference = 1.3900985917914e-09 s^-1,
    low = -5.145798608208269e-17 s^-1 },
  { shape = 0, tenor = 27.005 year, reference = 1.3907615059594036e-09 s^-1,
    low = -2.127832459414263e-17 s^-1 },
  { shape = 0, tenor = 27.504166666666666 year, reference = 1.391400328287773e-09 s^-1,
    low = 3.7556812223990137e-17 s^-1 },
  { shape = 0, tenor = 28.003333333333334 year, reference = 1.39201650206644e-09 s^-1,
    low = -3.146134806858893e-17 s^-1 },
  { shape = 0, tenor = 28.5025 year, reference = 1.3926110264961267e-09 s^-1,
    low = -3.088985560082094e-17 s^-1 },
  { shape = 0, tenor = 29.001666666666665 year, reference = 1.3931850117998579e-09 s^-1,
    low = 4.331025704843537e-17 s^-1 },
  { shape = 0, tenor = 29.500833333333333 year, reference = 1.3937396792229606e-09 s^-1,
    low = 8.742758098564893e-18 s^-1 },
  { shape = 0, tenor = 30.0 year, reference = 1.3942759169438546e-09 s^-1,
    low = -5.3061267250002373e-17 s^-1 },
  { shape = 1, tenor = 0.05 year, reference = 1.5739580749851712e-09 s^-1,
    low = 1.1523196687486337e-17 s^-1 },
  { shape = 1, tenor = 0.5491666666666667 year, reference = 1.4813422710702184e-09 s^-1,
    low = 4.667827759521957e-18 s^-1 },
  { shape = 1, tenor = 1.0483333333333333 year, reference = 1.4066451337058083e-09 s^-1,
    low = 3.191418313184741e-17 s^-1 },
  { shape = 1, tenor = 1.5475 year, reference = 1.3460040859669675e-09 s^-1,
    low = -4.9796871754455754e-17 s^-1 },
  { shape = 1, tenor = 2.0466666666666664 year, reference = 1.2964399553894168e-09 s^-1,
    low = 5.5053733587405804e-17 s^-1 },
  { shape = 1, tenor = 2.545833333333333 year, reference = 1.2556480299963368e-09 s^-1,
    low = -3.6653312619400517e-17 s^-1 },
  { shape = 1, tenor = 3.045 year, reference = 1.2218378531159146e-09 s^-1,
    low = 1.5657408993079417e-17 s^-1 },
  { shape = 1, tenor = 3.5441666666666665 year, reference = 1.1936142074731038e-09 s^-1,
    low = -5.194116047584839e-18 s^-1 },
  { shape = 1, tenor = 4.043333333333333 year, reference = 1.1698849666785804e-09 s^-1,
    low = -4.9920250705901714e-17 s^-1 },
  { shape = 1, tenor = 4.5424999999999995 year, reference = 1.149791817312007e-09 s^-1,
    low = -1.094366236980311e-17 s^-1 },
  { shape = 1, tenor = 5.041666666666666 year, reference = 1.132657523328362e-09 s^-1,
    low = 1.736143910524683e-17 s^-1 },
  { shape = 1, tenor = 5.540833333333333 year, reference = 1.1179451808729368e-09 s^-1,
    low = -3.622500842438791e-17 s^-1 },
  { shape = 1, tenor = 6.04 year, reference = 1.1052269099920409e-09 s^-1,
    low = 2.594190767635127e-17 s^-1 },
  { shape = 1, tenor = 6.539166666666667 year, reference = 1.0941606509717872e-09 s^-1,
    low = -4.000506004199396e-18 s^-1 },
  { shape = 1, tenor = 7.038333333333333 year, reference = 1.0844710685020686e-09 s^-1,
    low = -5.1711523557275096e-17 s^-1 },
  { shape = 1, tenor = 7.5375 year, reference = 1.075935562866448e-09 s^-1,
    low = -5.842195927498192e-18 s^-1 },
  { shape = 1, tenor = 8.036666666666667 year, reference = 1.0683735007788187e-09 s^-1,
    low = 1.013691890864443e-17 s^-1 },
  { shape = 1, tenor = 8.535833333333334 year, reference = 1.0616372225769055e-09 s^-1,
    low = 3.845438590667143e-17 s^-1 },
  { shape = 1, tenor = 9.035 year, reference = 1.055605602928722e-09 s^-1,
    low = 1.6910734859246288e-17 s^-1 },
  { shape = 1, tenor = 9.534166666666668 year, reference = 1.0501786107397493e-09 s^-1,
    low = -3.8669181550694297e-17 s^-1 },
  { shape = 1, tenor = 10.033333333333333 year, reference = 1.045273090305443e-09 s^-1,
    low = 4.938173296607254e-17 s^-1 },
  { shape = 1, tenor = 10.5325 year, reference = 1.040820096775974e-09 s^-1,
    low = 2.0749681736466115e-17 s^-1 },
  { shape = 1, tenor = 11.031666666666666 year, reference = 1.0367614544648518e-09 s^-1,
    low = 3.184046148693423e-17 s^-1 },
  { shape = 1, tenor = 11.530833333333334 year, reference = 1.033048313558993e-09 s^-1,
    low = 4.075188667548236e-17 s^-1 },
  { shape = 1, tenor = 12.030000000000001 year, reference = 1.029639262739579e-09 s^-1,
    low = 5.0325357447815884e-17 s^-1 },
  { shape = 1, tenor = 12.529166666666667 year, reference = 1.0264991079367292e-09 s^-1,
    low = 1.0357109424622371e-17 s^-1 },
  { shape = 1, tenor = 13.028333333333334 year, reference = 1.0235976510841738e-09 s^-1,
    low = -2.3691142612149582e-17 s^-1 },
  { shape = 1, tenor = 13.5275 year, reference = 1.0209089129631366e-09 s^-1,
    low = 2.6912906873286443e-17 s^-1 },
  { shape = 1, tenor = 14.026666666666667 year, reference = 1.018410689113125e-09 s^-1,
    low = 9.936569974019799e-18 s^-1 },
  { shape = 1, tenor = 14.525833333333333 year, reference = 1.0160835506312083e-09 s^-1,
    low = -2.840102795632649e-17 s^-1 },
  { shape = 1, tenor = 15.025 year, reference = 1.0139105111051094e-09 s^-1,
    low = 2.272802975517449e-17 s^-1 },
  { shape = 1, tenor = 15.524166666666666 year, reference = 1.011877026613206e-09 s^-1,
    low = -4.549784867489516e-17 s^-1 },
  { shape = 1, tenor = 16.023333333333333 year, reference = 1.009969885501505e-09 s^-1,
    low = 3.107984906135702e-17 s^-1 },
  { shape = 1, tenor = 16.5225 year, reference = 1.00817798553976e-09 s^-1,
    low = -5.116701041236614e-17 s^-1 },
  { shape = 1, tenor = 17.02166666666667 year, reference = 1.006491001653842e-09 s^-1,
    low = -5.110934268878139e-17 s^-1 },
  { shape = 1, tenor = 17.520833333333332 year, reference = 1.0049000520595541e-09 s^-1,
    low = -3.289745603471164e-17 s^-1 },
  { shape = 1, tenor = 18.02 year, reference = 1.003397143151119e-09 s^-1,
    low = 3.4601219794721814e-17 s^-1 },
  { shape = 1, tenor = 18.519166666666667 year, reference = 1.0019752805234816e-09 s^-1,
    low = 3.637957870237202e-17 s^-1 },
  { shape = 1, tenor = 19.018333333333334 year, reference = 1.000628024883099e-09 s^-1,
    low = 4.4925019483257287e-17 s^-1 },
  { shape = 1, tenor = 19.5175 year, reference = 9.993497140925456e-10 s^-1,
    low = 4.257034564486791e-18 s^-1 },
  { shape = 1, tenor = 20.016666666666666 year, reference = 9.981351301036057e-10 s^-1,
    low = -1.7159387005740954e-17 s^-1 },
  { shape = 1, tenor = 20.515833333333333 year, reference = 9.969796099795758e-10 s^-1,
    low = -6.090004763358359e-18 s^-1 },
  { shape = 1, tenor = 21.015 year, reference = 9.958789348729624e-10 s^-1,
    low = 4.74803193617765e-17 s^-1 },
  { shape = 1, tenor = 21.514166666666668 year, reference = 9.948294410477843e-10 s^-1,
    low = -1.1569240869103489e-17 s^-1 },
  { shape = 1, tenor = 22.013333333333332 year, reference = 9.9382746476806e-10 s^-1,
    low = 7.576629476670299e-18 s^-1 },
  { shape = 1, tenor = 22.5125 year, reference = 9.928698974093209e-10 s^-1,
    low = 4.8328831307966043e-17 s^-1 },
  { shape = 1, tenor = 23.011666666666667 year, reference = 9.91953963414005e-10 s^-1,
    low = -4.549076883603232e-18 s^-1 },
  { shape = 1, tenor = 23.510833333333334 year, reference = 9.910768872245512e-10 s^-1,
    low = -2.0944965844200084e-17 s^-1 },
  { shape = 1, tenor = 24.01 year, reference = 9.90236226350305e-10 s^-1,
    low = 1.6073518891501767e-17 s^-1 },
  { shape = 1, tenor = 24.509166666666665 year, reference = 9.894298713675198e-10 s^-1,
    low = -1.2102905540278813e-17 s^-1 },
  { shape = 1, tenor = 25.008333333333333 year, reference = 9.886557128524487e-10 s^-1,
    low = -4.62503315694122e-17 s^-1 },
  { shape = 1, tenor = 25.5075 year, reference = 9.879117524036474e-10 s^-1,
    low = 2.228032652043629e-17 s^-1 },
  { shape = 1, tenor = 26.006666666666668 year, reference = 9.871964357088814e-10 s^-1,
    low = 3.108786899098603e-18 s^-1 },
  { shape = 1, tenor = 26.50583333333333 year, reference = 9.865080974336138e-10 s^-1,
    low = -5.171485874950491e-17 s^-1 },
  { shape = 1, tenor = 27.005 year, reference = 9.858450722433076e-10 s^-1,
    low = 2.912778553379313e-17 s^-1 },
  { shape = 1, tenor = 27.504166666666666 year, reference = 9.852062499149383e-10 s^-1,
    low = -2.9707351284339635e-17 s^-1 },
  { shape = 1, tenor = 28.003333333333334 year, reference = 9.845900761362714e-10 s^-1,
    low = 3.931080900823943e-17 s^-1 },
  { shape = 1, tenor = 28.5025 year, reference = 9.839955517065846e-10 s^-1,
    low = 3.873931654047144e-17 s^-1 },
  { shape = 1, tenor = 29.001666666666665 year, reference = 9.834215664028534e-10 s^-1,
    low = -3.546079610878487e-17 s^-1 },
  { shape = 1, tenor = 29.500833333333333 year, reference = 9.828668989797507e-10 s^-1,
    low = -8.932977792998506e-19 s^-1 },
  { shape = 1, tenor = 30.0 year, reference = 9.823307722811592e-10 s^-1,
    low = -5.011157427286278e-17 s^-1 },
  { shape = 2, tenor = 0.05 year, reference = 9.76527525509141e-10 s^-1,
    low = 1.6094607034038194e-17 s^-1 },
  { shape = 2, tenor = 0.5491666666666667 year, reference = 1.1846394976089414e-09 s^-1,
    low = 3.506462622620872e-17 s^-1 },
  { shape = 2, tenor = 1.0483333333333333 year, reference = 1.3213939942247066e-09 s^-1,
    low = 7.294530282107052e-18 s^-1 },
  { shape = 2, tenor = 1.5475 year, reference = 1.4088044064664018e-09 s^-1,
    low = 5.510001268831692e-17 s^-1 },
  { shape = 2, tenor = 2.0466666666666664 year, reference = 1.462338694580012e-09 s^-1,
    low = -1.3312456181248765e-17 s^-1 },
  { shape = 2, tenor = 2.545833333333333 year, reference = 1.4928317471074593e-09 s^-1,
    low = 3.7394863494942055e-17 s^-1 },
  { shape = 2, tenor = 3.045 year, reference = 1.5078455151140702e-09 s^-1,
    low = -1.2114417412863713e-17 s^-1 },
  { shape = 2, tenor = 3.5441666666666665 year, reference = 1.5126330188408588e-09 s^-1,
    low = -2.471969869046742e-17 s^-1 },
  { shape = 2, tenor = 4.043333333333333 year, reference = 1.51082291122151e-09 s^-1,
    low = 1.6619519307152095e-17 s^-1 },
  { shape = 2, tenor = 4.5424999999999995 year, reference = 1.5049038681880234e-09 s^-1,
    low = 4.1161741434112586e-17 s^-1 },
  { shape = 2, tenor = 5.041666666666666 year, reference = 1.4965669814515081e-09 s^-1,
    low = 2.5648601011668543e-17 s^-1 },
  { shape = 2, tenor = 5.540833333333333 year, reference = 1.486947565076946e-09 s^-1,
    low = -3.251445817620979e-17 s^-1 },
  { shape = 2, tenor = 6.04 year, reference = 1.476795352672866e-09 s^-1,
    low = 7.782092869022345e-18 s^-1 },
  { shape = 2, tenor = 6.539166666666667 year, reference = 1.4665946235226102e-09 s^-1,
    low = 2.8421905167806717e-19 s^-1 },
  { shape = 2, tenor = 7.038333333333333 year, reference = 1.456647580333481e-09 s^-1,
    low = 1.2659139007287033e-17 s^-1 },
  { shape = 2, tenor = 7.5375 year, reference = 1.4471333020793509e-09 s^-1,
    low = -4.601027052075951e-17 s^-1 },
  { shape = 2, tenor = 8.036666666666667 year, reference = 1.4381480450964546e-09 s^-1,
    low = 1.7330871472890547e-17 s^-1 },
  { shape = 2, tenor = 8.535833333333334 year, reference = 1.4297341088820303e-09 s^-1,
    low = 9.223106843358111e-18 s^-1 },
  { shape = 2, tenor = 9.035 year, reference = 1.4218985988634358e-09 s^-1,
    low = -2.3059624956051072e-17 s^-1 },
  { shape = 2, tenor = 9.534166666666668 year, reference = 1.414626860096746e-09 s^-1,
    low = 4.878048681167102e-18 s^-1 },
  { shape = 2, tenor = 10.033333333333333 year, reference = 1.407891581095555e-09 s^-1,
    low = 4.725538910088863e-17 s^-1 },
  { shape = 2, tenor = 10.5325 year, reference = 1.401658678013007e-09 s^-1,
    low = 1.0457395147727075e-18 s^-1 },
  { shape = 2, tenor = 11.031666666666666 year, reference = 1.3958908473554743e-09 s^-1,
    low = 5.4078173316573014e-17 s^-1 },
  { shape = 2, tenor = 11.530833333333334 year, reference = 1.3905507856293298e-09 s^-1,
    low = -4.344085894099014e-17 s^-1 },
  { shape = 2, tenor = 12.030000000000001 year, reference = 1.3856017444524582e-09 s^-1,
    low = -1.0355168031724709e-18 s^-1 },
  { shape = 2, tenor = 12.529166666666667 year, reference = 1.3810094179333987e-09 s^-1,
    low = 1.3465057769374998e-17 s^-1 },
  { shape = 2, tenor = 13.028333333333334 year, reference = 1.376741831649042e-09 s^-1,
    low = -5.316102854059872e-17 s^-1 },
  { shape = 2, tenor = 13.5275 year, reference = 1.3727693426446308e-09 s^-1,
    low = 4.493130274719024e-17 s^-1 },
  { shape = 2, tenor = 14.026666666666667 year, reference = 1.3690655276121788e-09 s^-1,
    low = -2.6410710634154474e-17 s^-1 },
  { shape = 2, tenor = 14.525833333333333 year, reference = 1.365605850622842e-09 s^-1,
    low = 5.376236568486762e-17 s^-1 },
  { shape = 2, tenor = 15.025 year, reference = 1.3623687733499423e-09 s^-1,
    low = -6.005723744335637e-18 s^-1 },
  { shape = 2, tenor = 15.524166666666666 year, reference = 1.3593344228013393e-09 s^-1,
    low = 3.565334390305251e-17 s^-1 },
  { shape = 2, tenor = 16.023333333333333 year, reference = 1.3564853684755462e-09 s^-1,
    low = -2.1477206937541204e-17 s^-1 },
  { shape = 2, tenor = 16.5225 year, reference = 1.3538056231610085e-09 s^-1,
    low = -1.5293242728402947e-17 s^-1 },
  { shape = 2, tenor = 17.02166666666667 year, reference = 1.3512810870253134e-09 s^-1,
    low = -5.1571743268643435e-17 s^-1 },
  { shape = 2, tenor = 17.520833333333332 year, reference = 1.3488988814813752e-09 s^-1,
    low = -1.0831323797992896e-17 s^-1 },
  { shape = 2, tenor = 18.02 year, reference = 1.3466476822543427e-09 s^-1,
    low = -3.9479682893375805e-17 s^-1 },
  { shape = 2, tenor = 18.519166666666667 year, reference = 1.3445170532477846e-09 s^-1,
    low = -2.6411430281287395e-17 s^-1 },
  { shape = 2, tenor = 19.018333333333334 year, reference = 1.3424976685882939e-09 s^-1,
    low = 4.716790317058257e-17 s^-1 },
  { shape = 2, tenor = 19.5175 year, reference = 1.3405813126254884e-09 s^-1,
    low = -5.960915784143946e-18 s^-1 },
  { shape = 2, tenor = 20.016666666666666 year, reference = 1.3387602137981958e-09 s^-1,
    low = -1.3645535344144268e-17 s^-1 },
  { shape = 2, tenor = 20.515833333333333 year, reference = 1.3370274887236633e-09 s^-1,
    low = 2.253493271298011e-17 s^-1 },
  { shape = 2, tenor = 21.015 year, reference = 1.3353770311752555e-09 s^-1,
    low = -4.021038115928065e-17 s^-1 },
  { shape = 2, tenor = 21.514166666666668 year, reference = 1.333802956970942e-09 s^-1,
    low = 6.445432692043819e-20 s^-1 },
  { shape = 2, tenor = 22.013333333333332 year, reference = 1.3323002701071118e-09 s^-1,
    low = -3.7003977642118896e-17 s^-1 },
  { shape = 2, tenor = 22.5125 year, reference = 1.3308640856024567e-09 s^-1,
    low = 9.413972152259822e-18 s^-1 },
  { shape = 2, tenor = 23.011666666666667 year, reference = 1.329490184609483e-09 s^-1,
    low = 3.8943563977323037e-17 s^-1 },
  { shape = 2, tenor = 23.510833333333334 year, reference = 1.3281746813476047e-09 s^-1,
    low = -1.8637335421607825e-17 s^-1 },
  { shape = 2, tenor = 24.01 year, reference = 1.326913801058538e-09 s^-1,
    low = -1.8186149756490776e-17 s^-1 },
  { shape = 2, tenor = 24.509166666666665 year, reference = 1.3257042130732088e-09 s^-1,
    low = 3.5169532580215147e-17 s^-1 },
  { shape = 2, tenor = 25.008333333333333 year, reference = 1.3245430308117534e-09 s^-1,
    low = -4.280731138366843e-17 s^-1 },
  { shape = 2, tenor = 25.5075 year, reference = 1.3234271456497027e-09 s^-1,
    low = 2.509314757597796e-17 s^-1 },
  { shape = 2, tenor = 26.006666666666668 year, reference = 1.322354226118705e-09 s^-1,
    low = -4.439536250214978e-17 s^-1 },
  { shape = 2, tenor = 26.50583333333333 year, reference = 1.321321607683501e-09 s^-1,
    low = -5.0123447623375365e-18 s^-1 },
  { shape = 2, tenor = 27.005 year, reference = 1.3203271809203443e-09 s^-1,
    low = 1.2826031794856345e-17 s^-1 },
  { shape = 2, tenor = 27.504166666666666 year, reference = 1.3193688364054879e-09 s^-1,
    low = 4.1041939211635306e-17 s^-1 },
  { shape = 2, tenor = 28.003333333333334 year, reference = 1.3184446867597899e-09 s^-1,
    low = 3.7451495588399885e-17 s^-1 },
  { shape = 2, tenor = 28.5025 year, reference = 1.317552955626411e-09 s^-1,
    low = -1.611755467859164e-17 s^-1 },
  { shape = 2, tenor = 29.001666666666665 year, reference = 1.3166918666485117e-09 s^-1,
    low = -1.4388492426727146e-17 s^-1 },
  { shape = 2, tenor = 29.500833333333333 year, reference = 1.3158598655138576e-09 s^-1,
    low = 3.8901579598152295e-17 s^-1 },
  { shape = 2, tenor = 30.0 year, reference = 1.3150556199548191e-09 s^-1,
    low = 2.161684991419118e-17 s^-1 },
};

// The seam's tenors, x = t / tau from 0.1 to 2, seven of them within four roundings of a half, where the loading turns
// from its series to (1 - e^-x) / x; each the law in float64; the kernel's yield, and with the factors doubled.
struct crossing {
  bool seam; float<s> tenor; float<s^-1> reference; float<s^-1> low; float<s^-1> yld; float<s^-1> doubled; bool holds;
};
host table<crossing> crossings(capacity = 13) = {
  { seam = false, tenor = 0.15000000000000002 year, reference = 8.448481914058448e-10 s^-1,
    low = -1.735322851048663e-17 s^-1 },
  { seam = false, tenor = 0.44999999999999996 year, reference = 9.349041540929193e-10 s^-1,
    low = 1.8224906476911335e-17 s^-1 },
  { seam = false, tenor = 0.735 year, reference = 1.0045207998743422e-09 s^-1,
    low = -5.012185447351559e-17 s^-1 },
  { seam = true, tenor = 0.7499996423721313 year, reference = 1.0078103906963065e-09 s^-1,
    low = 1.778163031281152e-17 s^-1 },
  { seam = true, tenor = 0.7499998211860657 year, reference = 1.007810501718609e-09 s^-1,
    low = -5.423203552795278e-17 s^-1 },
  { seam = true, tenor = 0.7499999105930328 year, reference = 1.007810501718609e-09 s^-1,
    low = -3.4727722180160774e-17 s^-1 },
  { seam = true, tenor = 0.75 year, reference = 1.007810501718609e-09 s^-1,
    low = -1.5223407178007545e-17 s^-1 },
  { seam = true, tenor = 0.7500000894069672 year, reference = 1.007810501718609e-09 s^-1,
    low = 4.280906583374765e-18 s^-1 },
  { seam = true, tenor = 0.7500001788139343 year, reference = 1.007810501718609e-09 s^-1,
    low = 2.3785217863215238e-17 s^-1 },
  { seam = true, tenor = 0.7500003576278687 year, reference = 1.0078106127409114e-09 s^-1,
    low = -4.822846452116131e-17 s^-1 },
  { seam = false, tenor = 0.765 year, reference = 1.011065453582205e-09 s^-1,
    low = -2.289675640216183e-17 s^-1 },
  { seam = false, tenor = 1.0499999999999998 year, reference = 1.0667513539175388e-09 s^-1,
    low = 2.0800583122640178e-17 s^-1 },
  { seam = false, tenor = 3.0 year, reference = 1.2502521240520537e-09 s^-1,
    low = -9.59543407195803e-18 s^-1 },
};

// The sweep: the step, from 0 to 299 and round again; the tenor, a tenth of a year on from a twentieth; each curve's
// yield, and in percent for the chart; the normal and inverted curves' at the step before; and the humped curve's
// highest so far and the step it was at.
struct {
  integer step = -1; float<year> tenor; float<s^-1> normal; float<s^-1> inverted; float<s^-1> humped;
  float normal_percent; float inverted_percent; float humped_percent; float<s^-1> normal_before;
  float<s^-1> inverted_before; float<s^-1> highest; integer highest_at;
} sweep;

// The checks: every point of the three curves within 4 epsilons of the factors' sizes of the law in float64; the normal
// curve rising at every step, the inverted falling, and the humped one's peak inside the tenors; the short end level +
// slope, at no tenor and at 1e-8 years, and the long end the level and the slope's and curvature's loadings, both tau /
// t, each within 2 epsilons of the level; across the seam the curve within 4 epsilons of the law and its seven yields
// there within 4 epsilons of each other; and every factor doubled doubling the yield bit for bit.
struct { bool reference = true; bool shapes = true; bool ends = true; bool seam = true; bool linear = true; } checks;

// A strip of lamps the page draws, lit green while every check holds and red once one fails.
struct lamp { vector<float, 4> colour; };
lattice<lamp, 2> lamps(spacing = 1 m, boundary = wall);

vector<float, 4> lamp_colour(bool holds)
{
  return holds ? vector<float, 4>(0.15, 0.6, 0.3, 1.0) : vector<float, 4>(0.75, 0.15, 0.15, 1.0);
}

float eps() { return 1.0 / 8388608.0; }

float<s^-1> factor_of(integer shape, float<s^-1> normal, float<s^-1> inverted, float<s^-1> humped)
{
  if (shape == 0) return normal;
  if (shape == 1) return inverted;
  return humped;
}

// Within 4 epsilons of the curve's factors' sizes added, a second: the yield less the reference's rounding is exact, so
// the comparison rounds nothing that matters.
bool near(integer shape, float<s^-1> yld, float<s^-1> reference, float<s^-1> low)
{
  let bound = shape == 0 ? 9.821537532386216e-16 s^-1
              : (shape == 1 ? 7.555028871066321e-16 s^-1 : 1.3599051967919375e-15 s^-1);
  return abs(yld - reference - low) <= bound;
}

integer failing(table<bool> holds) { return count(holds) where !holds; }

bool seam_holds(table<bool> seam, table<float<s^-1>> yld)
{
  let highest = max(yld) where seam;
  let lowest = min(yld) where seam;
  return highest - lowest <= 1.133254330659948e-15 s^-1;
}

integer undoubled(table<float<s^-1>> yld, table<float<s^-1>> doubled)
{
  return count(yld) where doubled != 2.0 * yld;
}

bool ends(float<s> nothing, float<s> short, float<s> long, float<s> tau, float<s^-1> level, float<s^-1> slope,
          float<s^-1> curvature)
{
  let at_nothing = lusine.finance.nelson_siegel(tenor = nothing, level, slope, curvature, tau);
  let at_short = lusine.finance.nelson_siegel(tenor = short, level, slope, curvature, tau);
  let at_long = lusine.finance.nelson_siegel(tenor = long, level, slope, curvature, tau);
  return abs(at_nothing - (level + slope)) <= 2.0 * eps() * level
      && abs(at_short - (level + slope)) <= 2.0 * eps() * level
      && abs(at_long - (level + (slope + curvature) * tau / long)) <= 2.0 * eps() * level;
}

output table<lusine.widget> panels = {
  lusine.series { { panel = "the curves", chart = "yield, %", quantity = sweep.normal_percent, steps = 300,
                    against = sweep.tenor, label = "normal" } },
  lusine.series { { panel = "the curves", chart = "yield, %", quantity = sweep.inverted_percent, steps = 300,
                    against = sweep.tenor, label = "inverted" } },
  lusine.series { { panel = "the curves", chart = "yield, %", quantity = sweep.humped_percent, steps = 300,
                    against = sweep.tenor, label = "humped" } },
  lusine.value { { panel = "the curves", quantity = sweep.tenor, label = "tenor" } },
  lusine.value { { panel = "the curves", quantity = sweep.normal_percent, label = "normal, %" } },
  lusine.value { { panel = "the curves", quantity = sweep.inverted_percent, label = "inverted, %" } },
  lusine.value { { panel = "the curves", quantity = sweep.humped_percent, label = "humped, %" } },
  lusine.value { { panel = "the checks", quantity = checks.reference, label = "the law in float64" } },
  lusine.value { { panel = "the checks", quantity = checks.shapes, label = "normal, inverted and humped" } },
  lusine.value { { panel = "the checks", quantity = checks.ends, label = "the short end and the long" } },
  lusine.value { { panel = "the checks", quantity = checks.seam, label = "across the series' seam" } },
  lusine.value { { panel = "the checks", quantity = checks.linear, label = "linear in its factors" } },
};

void main()
{
  points.yld = lusine.finance.nelson_siegel(points.tenor,
                                            level = factor_of(points.shape, normal = settings.normal_level,
                                                              inverted = settings.inverted_level,
                                                              humped = settings.humped_level),
                                            slope = factor_of(points.shape, normal = settings.normal_slope,
                                                              inverted = settings.inverted_slope,
                                                              humped = settings.humped_slope),
                                            curvature = factor_of(points.shape, normal = settings.normal_curvature,
                                                                  inverted = settings.inverted_curvature,
                                                                  humped = settings.humped_curvature),
                                            settings.tau);
  points.holds = near(points.shape, points.yld, points.reference, points.low);
  crossings.yld = lusine.finance.nelson_siegel(crossings.tenor, settings.level, settings.slope, settings.curvature,
                                               settings.tau);
  crossings.doubled = lusine.finance.nelson_siegel(crossings.tenor, level = 2.0 * settings.level,
                                                   slope = 2.0 * settings.slope,
                                                   curvature = 2.0 * settings.curvature, settings.tau);
  crossings.holds = abs(crossings.yld - crossings.reference - crossings.low) <= 1.133254330659948e-15 s^-1;
  sweep.step = sweep.step >= 299 ? 0 : sweep.step + 1;
  sweep.tenor = 0.05 year + float(sweep.step) * 0.1 year;
  sweep.normal_before = sweep.normal;
  sweep.inverted_before = sweep.inverted;
  sweep.normal = lusine.finance.nelson_siegel(sweep.tenor, level = settings.normal_level,
                                              slope = settings.normal_slope, curvature = settings.normal_curvature,
                                              settings.tau);
  sweep.inverted = lusine.finance.nelson_siegel(sweep.tenor, level = settings.inverted_level,
                                                slope = settings.inverted_slope,
                                                curvature = settings.inverted_curvature, settings.tau);
  sweep.humped = lusine.finance.nelson_siegel(sweep.tenor, level = settings.humped_level,
                                              slope = settings.humped_slope, curvature = settings.humped_curvature,
                                              settings.tau);
  sweep.normal_percent = sweep.normal * 100.0 year;
  sweep.inverted_percent = sweep.inverted * 100.0 year;
  sweep.humped_percent = sweep.humped * 100.0 year;
  sweep.highest_at = sweep.step == 0 || sweep.humped > sweep.highest ? sweep.step : sweep.highest_at;
  sweep.highest = sweep.step == 0 || sweep.humped > sweep.highest ? sweep.humped : sweep.highest;
  checks.reference = checks.reference && failing(holds = points.holds) == 0;
  checks.shapes = checks.shapes
                  && (sweep.step == 0 || (sweep.normal > sweep.normal_before && sweep.inverted < sweep.inverted_before))
                  && (sweep.step < 299 || (sweep.highest_at > 0 && sweep.highest_at < 299));
  checks.ends = checks.ends && ends(settings.nothing, settings.short, settings.long, settings.tau, settings.level,
                                    settings.slope, settings.curvature);
  checks.seam = checks.seam && failing(holds = crossings.holds) == 0 && seam_holds(crossings.seam, crossings.yld);
  checks.linear = checks.linear && undoubled(crossings.yld, crossings.doubled) == 0;
  lamps.colour = lamp_colour(holds = checks.reference && checks.shapes && checks.ends && checks.seam && checks.linear);
}

The kernel's other proof (three hundred tenors a curve read back on the host) is on its proof page.