VariateIteratorPrimitive.java

  1. package org.drip.function.r1tor1solver;

  2. /*
  3.  * -*- mode: java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  4.  */

  5. /*!
  6.  * Copyright (C) 2020 Lakshmi Krishnamurthy
  7.  * Copyright (C) 2019 Lakshmi Krishnamurthy
  8.  * Copyright (C) 2018 Lakshmi Krishnamurthy
  9.  * Copyright (C) 2017 Lakshmi Krishnamurthy
  10.  * Copyright (C) 2016 Lakshmi Krishnamurthy
  11.  * Copyright (C) 2015 Lakshmi Krishnamurthy
  12.  * Copyright (C) 2014 Lakshmi Krishnamurthy
  13.  * Copyright (C) 2013 Lakshmi Krishnamurthy
  14.  * Copyright (C) 2012 Lakshmi Krishnamurthy
  15.  *
  16.  *  This file is part of DROP, an open-source library targeting analytics/risk, transaction cost analytics,
  17.  *      asset liability management analytics, capital, exposure, and margin analytics, valuation adjustment
  18.  *      analytics, and portfolio construction analytics within and across fixed income, credit, commodity,
  19.  *      equity, FX, and structured products. It also includes auxiliary libraries for algorithm support,
  20.  *      numerical analysis, numerical optimization, spline builder, model validation, statistical learning,
  21.  *      and computational support.
  22.  *  
  23.  *      https://lakshmidrip.github.io/DROP/
  24.  *  
  25.  *  DROP is composed of three modules:
  26.  *  
  27.  *  - DROP Product Core - https://lakshmidrip.github.io/DROP-Product-Core/
  28.  *  - DROP Portfolio Core - https://lakshmidrip.github.io/DROP-Portfolio-Core/
  29.  *  - DROP Computational Core - https://lakshmidrip.github.io/DROP-Computational-Core/
  30.  *
  31.  *  DROP Product Core implements libraries for the following:
  32.  *  - Fixed Income Analytics
  33.  *  - Loan Analytics
  34.  *  - Transaction Cost Analytics
  35.  *
  36.  *  DROP Portfolio Core implements libraries for the following:
  37.  *  - Asset Allocation Analytics
  38.  *  - Asset Liability Management Analytics
  39.  *  - Capital Estimation Analytics
  40.  *  - Exposure Analytics
  41.  *  - Margin Analytics
  42.  *  - XVA Analytics
  43.  *
  44.  *  DROP Computational Core implements libraries for the following:
  45.  *  - Algorithm Support
  46.  *  - Computation Support
  47.  *  - Function Analysis
  48.  *  - Model Validation
  49.  *  - Numerical Analysis
  50.  *  - Numerical Optimizer
  51.  *  - Spline Builder
  52.  *  - Statistical Learning
  53.  *
  54.  *  Documentation for DROP is Spread Over:
  55.  *
  56.  *  - Main                     => https://lakshmidrip.github.io/DROP/
  57.  *  - Wiki                     => https://github.com/lakshmiDRIP/DROP/wiki
  58.  *  - GitHub                   => https://github.com/lakshmiDRIP/DROP
  59.  *  - Repo Layout Taxonomy     => https://github.com/lakshmiDRIP/DROP/blob/master/Taxonomy.md
  60.  *  - Javadoc                  => https://lakshmidrip.github.io/DROP/Javadoc/index.html
  61.  *  - Technical Specifications => https://github.com/lakshmiDRIP/DROP/tree/master/Docs/Internal
  62.  *  - Release Versions         => https://lakshmidrip.github.io/DROP/version.html
  63.  *  - Community Credits        => https://lakshmidrip.github.io/DROP/credits.html
  64.  *  - Issues Catalog           => https://github.com/lakshmiDRIP/DROP/issues
  65.  *  - JUnit                    => https://lakshmidrip.github.io/DROP/junit/index.html
  66.  *  - Jacoco                   => https://lakshmidrip.github.io/DROP/jacoco/index.html
  67.  *
  68.  *  Licensed under the Apache License, Version 2.0 (the "License");
  69.  *      you may not use this file except in compliance with the License.
  70.  *  
  71.  *  You may obtain a copy of the License at
  72.  *      http://www.apache.org/licenses/LICENSE-2.0
  73.  *  
  74.  *  Unless required by applicable law or agreed to in writing, software
  75.  *      distributed under the License is distributed on an "AS IS" BASIS,
  76.  *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  77.  *  
  78.  *  See the License for the specific language governing permissions and
  79.  *      limitations under the License.
  80.  */

  81. /**
  82.  * <i>VariateIteratorPrimitive</i> implements the various Primitive Variate Iterator routines.
  83.  *
  84.  * VariateIteratorPrimitive implements the following iteration primitives:
  85.  * <br>
  86.  * <ul>
  87.  *  <li>
  88.  *      Bisection
  89.  *  </li>
  90.  *  <li>
  91.  *      False Position
  92.  *  </li>
  93.  *  <li>
  94.  *      Quadratic
  95.  *  </li>
  96.  *  <li>
  97.  *      Inverse Quadratic
  98.  *  </li>
  99.  *  <li>
  100.  *      Ridder
  101.  *  </li>
  102.  * </ul>
  103.  * <br>
  104.  * It may be readily enhanced to accommodate additional primitives.
  105.  *
  106.  *  <br><br>
  107.  *  <ul>
  108.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ComputationalCore.md">Computational Core Module</a></li>
  109.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/NumericalAnalysisLibrary.md">Numerical Analysis Library</a></li>
  110.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/function/README.md">R<sup>d</sup> To R<sup>d</sup> Function Analysis</a></li>
  111.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/function/r1tor1solver/README.md">Built-in R<sup>1</sup> To R<sup>1</sup> Solvers</a></li>
  112.  *  </ul>
  113.  *
  114.  * @author Lakshmi Krishnamurthy
  115.  */

  116. public class VariateIteratorPrimitive {

  117.     /**
  118.      * Bisection
  119.      */

  120.     public static int BISECTION = 0;

  121.     /**
  122.      * False Position
  123.      */

  124.     public static int FALSE_POSITION = 1;

  125.     /**
  126.      * Quadratic Interpolation
  127.      */

  128.     public static int QUADRATIC_INTERPOLATION = 2;

  129.     /**
  130.      * Inverse Quadratic Interpolation
  131.      */

  132.     public static int INVERSE_QUADRATIC_INTERPOLATION = 3;

  133.     /**
  134.      * Ridder's Method
  135.      */

  136.     public static int RIDDER = 4;

  137.     /**
  138.      * Iterate for the next variate using bisection
  139.      *
  140.      * @param dblX1 Left variate
  141.      * @param dblX2 Right variate
  142.      *
  143.      * @return The next variate
  144.      *
  145.      * @throws java.lang.Exception Thrown if inputs are invalid
  146.      */

  147.     public static final double Bisection (
  148.         final double dblX1,
  149.         final double dblX2)
  150.         throws java.lang.Exception
  151.     {
  152.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblX1) || !org.drip.numerical.common.NumberUtil.IsValid
  153.             (dblX2))
  154.             throw new java.lang.Exception ("VariateIteratorPrimitive::Bisection => Invalid inputs " + dblX2);

  155.         return 0.5 * (dblX1 + dblX2);
  156.     }

  157.     /**
  158.      * Iterate for the next variate using false position
  159.      *
  160.      * @param dblX1 Left variate
  161.      * @param dblX2 Right variate
  162.      * @param dblY1 Left OF value
  163.      * @param dblY2 Right OF value
  164.      *
  165.      * @return The next variate
  166.      *
  167.      * @throws java.lang.Exception Thrown if inputs are invalid
  168.      */

  169.     public static final double FalsePosition (
  170.         final double dblX1,
  171.         final double dblX2,
  172.         final double dblY1,
  173.         final double dblY2)
  174.         throws java.lang.Exception
  175.     {
  176.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblX1) || !org.drip.numerical.common.NumberUtil.IsValid
  177.             (dblX2) || !org.drip.numerical.common.NumberUtil.IsValid (dblY1) ||
  178.                 !org.drip.numerical.common.NumberUtil.IsValid (dblY2))
  179.             throw new java.lang.Exception ("VariateIteratorPrimitive::FalsePosition => Invalid inputs");

  180.         return dblX1 + ((dblX1 - dblX2) / (dblY2 - dblY1) * dblY1);
  181.     }

  182.     /**
  183.      * Iterate for the next variate using quadratic interpolation
  184.      *
  185.      * @param dblX1 Left variate
  186.      * @param dblX2 Intermediate variate
  187.      * @param dblX3 Right variate
  188.      * @param dblY1 Left OF value
  189.      * @param dblY2 Intermediate OF value
  190.      * @param dblY3 Right OF value
  191.      *
  192.      * @return The next variate
  193.      *
  194.      * @throws java.lang.Exception Thrown if inputs are invalid
  195.      */

  196.     public static final double QuadraticInterpolation (
  197.         final double dblX1,
  198.         final double dblX2,
  199.         final double dblX3,
  200.         final double dblY1,
  201.         final double dblY2,
  202.         final double dblY3)
  203.         throws java.lang.Exception
  204.     {
  205.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblX1) || !org.drip.numerical.common.NumberUtil.IsValid
  206.             (dblX2) || !org.drip.numerical.common.NumberUtil.IsValid (dblX3) ||
  207.                 !org.drip.numerical.common.NumberUtil.IsValid (dblY1) || !org.drip.numerical.common.NumberUtil.IsValid
  208.                     (dblY2) || !org.drip.numerical.common.NumberUtil.IsValid (dblY3))
  209.             throw new java.lang.Exception
  210.                 ("VariateIteratorPrimitive.QuadraticInterpolation => Invalid inputs!");

  211.         double dblA = dblY1 / (dblX1 - dblX2) / (dblX1 - dblX3);
  212.         dblA       += dblY2 / (dblX2 - dblX3) / (dblX2 - dblX1);
  213.         dblA       += dblY3 / (dblX3 - dblX1) / (dblX3 - dblX2);
  214.         double dblB = -1. * (dblX2 + dblX3) * dblY1 / (dblX1 - dblX2) / (dblX1 - dblX3);
  215.         dblB       -=       (dblX3 + dblX1) * dblY2 / (dblX2 - dblX3) / (dblX2 - dblX1);
  216.         dblB       -=       (dblX1 + dblX2) * dblY3 / (dblX3 - dblX1) / (dblX3 - dblX2);
  217.         double dblC = dblX2 * dblX3 * dblY1 / (dblX1 - dblX2) / (dblX1 - dblX3);
  218.         dblC       += dblX3 * dblX1 * dblY2 / (dblX2 - dblX3) / (dblX2 - dblX1);
  219.         dblC       += dblX1 * dblX2 * dblY3 / (dblX3 - dblX1) / (dblX3 - dblX2);
  220.         double dblSQRTArg = dblB * dblB - 4. * dblA * dblC;

  221.         if (0. > dblSQRTArg)
  222.             throw new java.lang.Exception
  223.                 ("VariateIteratorPrimitive.QuadraticInterpolation => No real roots!");

  224.         double dblSQRT = java.lang.Math.sqrt (dblSQRTArg);

  225.         double dblRoot1 = (-1. * dblB + dblSQRT) / 2. / dblA;
  226.         double dblRoot2 = (-1. * dblB - dblSQRT) / 2. / dblA;

  227.         if (dblX1 > dblRoot1 || dblX3 < dblRoot1) return dblRoot2;

  228.         if (dblX1 > dblRoot2 || dblX3 < dblRoot2) return dblRoot1;

  229.         return java.lang.Math.abs (dblX2 - dblRoot1) < java.lang.Math.abs (dblX2 - dblRoot2) ? dblRoot1 :
  230.             dblRoot2;
  231.     }

  232.     /**
  233.      * Iterate for the next variate using inverse quadratic interpolation
  234.      *
  235.      * @param dblX1 Left variate
  236.      * @param dblX2 Intermediate variate
  237.      * @param dblX3 Right variate
  238.      * @param dblY1 Left OF value
  239.      * @param dblY2 Intermediate OF value
  240.      * @param dblY3 Right OF value
  241.      *
  242.      * @return The next variate
  243.      *
  244.      * @throws java.lang.Exception Thrown if inputs are invalid
  245.      */

  246.     public static final double InverseQuadraticInterpolation (
  247.         final double dblX1,
  248.         final double dblX2,
  249.         final double dblX3,
  250.         final double dblY1,
  251.         final double dblY2,
  252.         final double dblY3)
  253.         throws java.lang.Exception
  254.     {
  255.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblX1) || !org.drip.numerical.common.NumberUtil.IsValid
  256.             (dblX2) || !org.drip.numerical.common.NumberUtil.IsValid (dblX3) ||
  257.                 !org.drip.numerical.common.NumberUtil.IsValid (dblY1) || !org.drip.numerical.common.NumberUtil.IsValid
  258.                     (dblY2) || !org.drip.numerical.common.NumberUtil.IsValid (dblY3))
  259.             throw new java.lang.Exception
  260.                 ("VariateIteratorPrimitive.InverseQuadraticInterpolation => Invalid inputs!");

  261.         double dblNextRoot = (dblY2 * dblY3 * dblX1 / (dblY1 - dblY2) / (dblY1 - dblY3));
  262.         dblNextRoot       += (dblY3 * dblY1 * dblX2 / (dblY2 - dblY3) / (dblY2 - dblY1));
  263.         dblNextRoot       += (dblY1 * dblY2 * dblX3 / (dblY3 - dblY1) / (dblY3 - dblY2));
  264.         return dblNextRoot;
  265.     }

  266.     /**
  267.      * Iterate for the next variate using Ridder's method
  268.      *
  269.      * @param dblX1 Left variate
  270.      * @param dblX2 Intermediate variate
  271.      * @param dblX3 Right variate
  272.      * @param dblY1 Left OF value
  273.      * @param dblY2 Intermediate OF value
  274.      * @param dblY3 Right OF value
  275.      *
  276.      * @return The next variate
  277.      *
  278.      * @throws java.lang.Exception Thrown if inputs are invalid
  279.      */

  280.     public static final double Ridder (
  281.         final double dblX1,
  282.         final double dblX2,
  283.         final double dblX3,
  284.         final double dblY1,
  285.         final double dblY2,
  286.         final double dblY3)
  287.         throws java.lang.Exception
  288.     {
  289.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblX1) || !org.drip.numerical.common.NumberUtil.IsValid
  290.             (dblX2) || !org.drip.numerical.common.NumberUtil.IsValid (dblX3) ||
  291.                 !org.drip.numerical.common.NumberUtil.IsValid (dblY1) || !org.drip.numerical.common.NumberUtil.IsValid
  292.                     (dblY2) || !org.drip.numerical.common.NumberUtil.IsValid (dblY3))
  293.             throw new java.lang.Exception ("VariateIteratorPrimitive.Ridder => Invalid inputs!");

  294.         double dblSQRTArg = dblY3 * dblY3 - dblY1 * dblY2;

  295.         if (0. > dblSQRTArg)
  296.             throw new java.lang.Exception ("VariateIteratorPrimitive.Ridder => No real roots!");

  297.         return dblX3 + (dblX3 - dblX1) * dblY3 * java.lang.Math.signum (dblY1 - dblY2) / java.lang.Math.sqrt
  298.             (dblSQRTArg);
  299.     }

  300.     /**
  301.      * Iterate for the next variate using the multi-function method
  302.      *
  303.      * @param dblX1 Left variate
  304.      * @param dblX2 Intermediate variate
  305.      * @param dblX3 Right variate
  306.      * @param dblY1 Left OF value
  307.      * @param dblY2 Intermediate OF value
  308.      * @param dblY3 Right OF value
  309.      * @param of Objective Function
  310.      * @param dblOFTarget OF Target
  311.      * @param rfop Root Finder Output
  312.      *
  313.      * @return The next variate
  314.      *
  315.      * @throws java.lang.Exception Thrown if inputs are invalid
  316.      */

  317.     public static final double MultiFunction (
  318.         final double dblX1,
  319.         final double dblX2,
  320.         final double dblX3,
  321.         final double dblY1,
  322.         final double dblY2,
  323.         final double dblY3,
  324.         final org.drip.function.definition.R1ToR1 of,
  325.         final double dblOFTarget,
  326.         final org.drip.function.r1tor1solver.FixedPointFinderOutput rfop)
  327.         throws java.lang.Exception
  328.     {
  329.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblX1) || !org.drip.numerical.common.NumberUtil.IsValid
  330.             (dblX2) || !org.drip.numerical.common.NumberUtil.IsValid (dblX3) ||
  331.                 !org.drip.numerical.common.NumberUtil.IsValid (dblY1) || !org.drip.numerical.common.NumberUtil.IsValid
  332.                     (dblY2) || !org.drip.numerical.common.NumberUtil.IsValid (dblY3) ||
  333.                         !org.drip.numerical.common.NumberUtil.IsValid (dblOFTarget) || null == rfop || null == of)
  334.             throw new java.lang.Exception ("VariateIteratorPrimitive.MultiFunction => Invalid inputs!");

  335.         double dblNextRoot = Bisection (dblX1, dblX2);

  336.         if (!rfop.incrOFCalcs())
  337.             throw new java.lang.Exception
  338.                 ("VariateIteratorPrimitive.MultiFunction => Cannot increment rfop!");

  339.         double dblTargetDiff = java.lang.Math.abs (of.evaluate (dblNextRoot) - dblOFTarget);

  340.         try {
  341.             double dblRootSecant = FalsePosition (dblX1, dblX2, dblY1, dblY2);

  342.             if (!rfop.incrOFCalcs())
  343.                 throw new java.lang.Exception
  344.                     ("VariateIteratorPrimitive.MultiFunction => Cannot increment rfop!");

  345.             double dblTargetDiffSecant = java.lang.Math.abs (of.evaluate (dblRootSecant) - dblOFTarget);

  346.             if (dblTargetDiffSecant < dblTargetDiff) {
  347.                 dblNextRoot = dblRootSecant;
  348.                 dblTargetDiff = dblTargetDiffSecant;
  349.             }
  350.         } catch (java.lang.Exception e) {
  351.             // e.printStackTrace();
  352.         }

  353.         try {
  354.             double dblRootQuadraticInterpolation = QuadraticInterpolation (dblX1, dblX2, dblX3, dblY1, dblY2,
  355.                 dblY3);

  356.             if (!rfop.incrOFCalcs())
  357.                 throw new java.lang.Exception
  358.                     ("VariateIteratorPrimitive.MultiFunction => Cannot increment rfop!");

  359.             double dblTargetDiffQuadraticInterpolation = java.lang.Math.abs (of.evaluate
  360.                 (dblRootQuadraticInterpolation) - dblOFTarget);

  361.             if (dblTargetDiffQuadraticInterpolation < dblTargetDiff) {
  362.                 dblNextRoot = dblRootQuadraticInterpolation;
  363.                 dblTargetDiff = dblTargetDiffQuadraticInterpolation;
  364.             }
  365.         } catch (java.lang.Exception e) {
  366.             // e.printStackTrace();
  367.         }

  368.         try {
  369.             double dblRootInverseQuadraticInterpolation = QuadraticInterpolation (dblX1, dblX2, dblX3, dblY1,
  370.                 dblY2, dblY3);

  371.             if (!rfop.incrOFCalcs())
  372.                 throw new java.lang.Exception
  373.                     ("VariateIteratorPrimitive.MultiFunction => Cannot increment rfop!");

  374.             double dblTargetDiffInverseQuadraticInterpolation = java.lang.Math.abs (of.evaluate
  375.                 (dblRootInverseQuadraticInterpolation) - dblOFTarget);

  376.             if (dblTargetDiffInverseQuadraticInterpolation < dblTargetDiff) {
  377.                 dblNextRoot = dblRootInverseQuadraticInterpolation;
  378.                 dblTargetDiff = dblTargetDiffInverseQuadraticInterpolation;
  379.             }
  380.         } catch (java.lang.Exception e) {
  381.             // e.printStackTrace();
  382.         }

  383.         try {
  384.             double dblRootRidder = Ridder (dblX1, dblX2, dblX3, dblY1, dblY2, dblY3);

  385.             if (!rfop.incrOFCalcs())
  386.                 throw new java.lang.Exception
  387.                     ("VariateIteratorPrimitive.MultiFunction => Cannot increment rfop!");

  388.             double dblTargetDiffRidder = java.lang.Math.abs (of.evaluate (dblRootRidder) - dblOFTarget);

  389.             if (dblTargetDiffRidder < dblTargetDiff) {
  390.                 dblNextRoot = dblRootRidder;
  391.                 dblTargetDiff = dblTargetDiffRidder;
  392.             }
  393.         } catch (java.lang.Exception e) {
  394.             // e.printStackTrace();
  395.         }

  396.         return dblNextRoot;
  397.     }
  398. }