ift_1dim#

rateslib.dual.ift_1dim(s, s_tgt, h, ini_h_args=(), max_iter=50, func_tol=1e-14, conv_tol=1e-09, raise_on_fail=True)#

Use the inverse function theorem to determine a function value of one variable.

Parameters:
  • s (Callable[DualTypes, DualTypes]) – The known inverse function of g such that g(s(x))=x. Of the signature: s(x).

  • s_tgt (DualTypes) – The value of s for which g is to be found.

  • h (Callable, string) – The iterative function to use to determine the solution g. See notes.

  • ini_h_args – Initial arguments passed to the iterative function, h.

  • max_iter (int > 1) – Number of maximum iterations to perform.

  • func_tol (float, optional) – The absolute function tolerance to reach before exiting.

  • conv_tol (float, optional) – The convergence tolerance for subsequent iterations of g, passed to h to implement.

  • raise_on_fail (bool, optional) – If False will return a solver result dict with state and message indicating failure.

Notes

Available iterative methods

  • ‘bisection’: requires ini_h_args to be a tuple of two floats defining the interval. The interval will be halved in each iteration and the relevant interval side kept.

  • ‘modified_dekker’: Requires ini_h_args to be a tuple of two floats defining the interval. For info see Halving Interval for Dekker.

  • ‘modified_brent’: Requires ini_h_args to be a tuple of two floats defining the interval. For info see Halving Interval for Brent.

  • ‘ytm_quadratic’: Requires ini_h_args to be a tuple of three floats defining the interval and interior point. This algorithm utilises sequential quadratic approximation and is specifically tuned for solving bond yield-to-maturity.

Mathematical background

This method is used to find the value of g from s in the one-dimensional equation:

\[g(s) \qquad \text{where,} \qquad s(g) \; \text{is a known analytical inverse of} \; g.\]

\(g(s)\) is not analytical and hence requires iterations to determine.

What is ``h``

h() is a function that is used to perform iterations to determine g from s. If a custom function is provided, it must conform to the following signature:

h(s, s_target, conv_tol, *h_args) -> (g_i, f_i, state, *h_args_i)

The input parameters provide:

  • s: The inverse function of g such that g(s(x))=x.

  • s_target: The target value of s for which g is to be found.

  • conv_tol: The convergence tolerance which is measured internally by h.

  • h_args: Additional arguments passed to h which facilitate its internal operation.

The output parameters provide:

  • g_i: The value of g at the current iteration, representative of \(g(s_i)\).

  • f_i: A measure of error in the iteration

  • state: A state flag return from the iteration as indicator to the controlling process.

  • h_args_i: Arguments passed to the next iteration of h.

state flag returns are:

  • -2: The algorithm failed for an internal reason.

  • 1: conv_tol has been satisfied and the solution is considered to have converged.

  • None: The algorithm has not yet converged and will continue.

AD Implementation

The AD order of the solution is determined by the AD order of the s_tgt input.

Examples

The most prevalent use of this technique in rateslib is to solve bond yield-to-maturity from a given price. Suppose we develop a formula, s(g) which determines the price (s) of a 2y bond with 3% annual coupon given its ytm (g):

\[s(g) = \frac{3}{1+g/100} + \frac{103}{(1+g/100)^2}\]

Then we use the bisection method to discover the ytm given a price of 101:

In [1]: from rateslib.dual import ift_1dim, Dual

In [2]: def s(g):
   ...:      return 3 / (1 + g / 100) + 103 / (1 + g / 100) ** 2
   ...: 

# solve for a bond price of 101 with lower and upper ytm bounds of 2.0 and 3.0.
In [3]: result = ift_1dim(s, Dual(101.0, ["price"], []), "bisection", (2.0, 3.0))

In [4]: print(result)
{'status': 'SUCCESS', 'state': 1, 'g': <Dual: 2.481314, (price), [-0.5]>, 'iterations': 30, 'time': 0.00014901161193847656}