Skip to content

_PolyStretch

Description

_PolyStretch finds the stretch around a point on which a polynomial keeps rising (or keeps falling), i.e. the nearest turning points on each side. PolyInv uses it so that an inverse prediction stays on the same branch of the calibration curve.

Used by: PolyInv

Calls: _Bisect

Source Code

_PolyStretch = LAMBDA(
    b, // polynomial coefficients as a row, b_0 to b_p
    x0, // a point inside the stretch
    xmin, // smallest x in the data
    xmax, // largest x in the data
    LET(
        p, COLUMNS(b) - 1,
        R, xmax - xmin,
        // slope of the polynomial, elementwise in x (avoids 0^0, an error in Excel)
        dydx, LAMBDA(x,
            IF(
                p = 1,
                INDEX(b, 1, 2) + 0 * x,
                MMULT(HSTACK(1 + 0 * x, x ^ SEQUENCE(1, p - 1)), TRANSPOSE(SEQUENCE(1, p) * DROP(b, , 1)))
            )
        ),
        // grid: linear across the data range +/- one range, then geometric
        // from R/10 out to 1e6*R beyond each end; x0 itself is included
        tail, R / 10 * 10 ^ (7 * SEQUENCE(500, 1, 0) / 499),
        xs, SORT(VSTACK(xmin - R - tail, SEQUENCE(2000, 1, xmin - R, 3 * R / 1999), xmax + R + tail, x0)),
        n, ROWS(xs),
        idx, SEQUENCE(n),
        i0, XMATCH(x0, xs),
        s0, SIGN(INDEX(dydx(x0), 1, 1)),
        bad, SIGN(dydx(xs)) <> s0,
        // nearest grid points where the slope has the other sign
        lo_i, MAX(FILTER(idx, bad * (idx < i0), 0)),
        hi_i, MIN(FILTER(idx, bad * (idx > i0), n + 1)),
        lo_end, IF(lo_i = 0, INDEX(xs, 1), _Bisect(dydx, INDEX(xs, lo_i + 1), INDEX(xs, lo_i))),
        hi_end, IF(hi_i = n + 1, INDEX(xs, n), _Bisect(dydx, INDEX(xs, hi_i - 1), INDEX(xs, hi_i))),
        HSTACK(lo_end, hi_end)
    )
);