R1ToR1Integrator.java

  1. package org.drip.numerical.integration;

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

  80. /**
  81.  * <i>R1ToR1Integrator</i> implements the following routines for integrating the R<sup>1</sup> To
  82.  * R<sup>1</sup> objective Function.
  83.  *
  84.  * <br><br>
  85.  *  <ul>
  86.  *      <li>
  87.  *          Linear Quadrature
  88.  *      </li>
  89.  *      <li>
  90.  *          Mid-Point Scheme
  91.  *      </li>
  92.  *      <li>
  93.  *          Trapezoidal Scheme
  94.  *      </li>
  95.  *      <li>
  96.  *          Simpson/Simpson38 schemes
  97.  *      </li>
  98.  *      <li>
  99.  *          Boole Scheme
  100.  *      </li>
  101.  *  </ul>
  102.  *
  103.  * <br><br>
  104.  *  <ul>
  105.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ComputationalCore.md">Computational Core Module</a></li>
  106.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/NumericalAnalysisLibrary.md">Numerical Analysis Library</a></li>
  107.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/numerical/README.md">Numerical Quadrature, Differentiation, Eigenization, Linear Algebra, and Utilities</a></li>
  108.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/numerical/integration/README.md">R<sup>1</sup> R<sup>d</sup> Numerical Integration Schemes</a></li>
  109.  *  </ul>
  110.  * <br><br>
  111.  *
  112.  * @author Lakshmi Krishnamurthy
  113.  */

  114. public class R1ToR1Integrator {
  115.     private final static int NUM_QUAD = 10000;

  116.     /**
  117.      * Compute the function's integral within the specified limits using the LinearQuadrature technique.
  118.      *
  119.      * @param funcR1ToR1 R1ToR1 Function
  120.      * @param dblLeft Left Variate
  121.      * @param dblRight Right Variate
  122.      *
  123.      * @return The Integral
  124.      *
  125.      * @throws java.lang.Exception Thrown if the error cannot be computed
  126.      */

  127.     public static final double LinearQuadrature (
  128.         final org.drip.function.definition.R1ToR1 funcR1ToR1,
  129.         final double dblLeft,
  130.         final double dblRight)
  131.         throws java.lang.Exception
  132.     {
  133.         if (null == funcR1ToR1 || !org.drip.numerical.common.NumberUtil.IsValid (dblLeft) ||
  134.             !org.drip.numerical.common.NumberUtil.IsValid (dblRight) || dblLeft > dblRight)
  135.             throw new java.lang.Exception ("R1ToR1Integrator::LinearQuadrature => Invalid Inputs");

  136.         if (dblLeft == dblRight) return 0.;

  137.         double dblWidth = (dblRight - dblLeft) / NUM_QUAD;
  138.         double dblX = dblLeft + dblWidth;
  139.         double dblAUArea = 0.;

  140.         while (dblX <= dblRight) {
  141.             double dblY = funcR1ToR1.evaluate (dblX - 0.5 * dblWidth);

  142.             if (!org.drip.numerical.common.NumberUtil.IsValid (dblLeft))
  143.                 throw new java.lang.Exception
  144.                     ("R1ToR1Integrator::LinearQuadrature => Cannot calculate an intermediate Y");

  145.             dblAUArea += dblY * dblWidth;
  146.             dblX += dblWidth;
  147.         }

  148.         return dblAUArea;
  149.     }

  150.     /**
  151.      * Compute the function's integral within the specified limits using the Mid-point rule.
  152.      *
  153.      * @param funcR1ToR1 R1ToR1 Function
  154.      * @param dblLeft Left Variate
  155.      * @param dblRight Right Variate
  156.      *
  157.      * @return The Integral
  158.      *
  159.      * @throws java.lang.Exception Thrown if the error cannot be computed
  160.      */

  161.     public static final double MidPoint (
  162.         final org.drip.function.definition.R1ToR1 funcR1ToR1,
  163.         final double dblLeft,
  164.         final double dblRight)
  165.         throws java.lang.Exception
  166.     {
  167.         if (null == funcR1ToR1 || !org.drip.numerical.common.NumberUtil.IsValid (dblLeft) ||
  168.             !org.drip.numerical.common.NumberUtil.IsValid (dblRight) || dblLeft > dblRight)
  169.             throw new java.lang.Exception ("R1ToR1Integrator::MidPoint => Invalid Inputs");

  170.         if (dblLeft == dblRight) return 0.;

  171.         double dblYMid = funcR1ToR1.evaluate (0.5 * (dblLeft + dblRight));

  172.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblYMid))
  173.             throw new java.lang.Exception ("R1ToR1Integrator::MidPoint => Cannot calculate Y at " + 0.5 *
  174.                 (dblLeft + dblRight));

  175.         return (dblRight - dblLeft) * dblYMid;
  176.     }

  177.     /**
  178.      * Compute the function's integral within the specified limits using the Trapezoidal rule.
  179.      *
  180.      * @param funcR1ToR1 R1ToR1 Function
  181.      * @param dblLeft Left Variate
  182.      * @param dblRight Right Variate
  183.      *
  184.      * @return The Integral
  185.      *
  186.      * @throws java.lang.Exception Thrown if the error cannot be computed
  187.      */

  188.     public static final double Trapezoidal (
  189.         final org.drip.function.definition.R1ToR1 funcR1ToR1,
  190.         final double dblLeft,
  191.         final double dblRight)
  192.         throws java.lang.Exception
  193.     {
  194.         if (null == funcR1ToR1 || !org.drip.numerical.common.NumberUtil.IsValid (dblLeft) ||
  195.             !org.drip.numerical.common.NumberUtil.IsValid (dblRight) || dblLeft > dblRight)
  196.             throw new java.lang.Exception ("R1ToR1Integrator::Trapezoidal => Invalid Inputs");

  197.         if (dblLeft == dblRight) return 0.;

  198.         double dblYLeft = funcR1ToR1.evaluate (dblLeft);

  199.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblYLeft))
  200.             throw new java.lang.Exception ("R1ToR1Integrator::Trapezoidal => Cannot calculate Y at " +
  201.                 dblLeft);

  202.         double dblYRight = funcR1ToR1.evaluate (dblRight);

  203.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblYLeft))
  204.             throw new java.lang.Exception ("R1ToR1Integrator::Trapezoidal => Cannot calculate Y at " +
  205.                 dblRight);

  206.         return 0.5 * (dblRight - dblLeft) * (dblYLeft + dblYRight);
  207.     }

  208.     /**
  209.      * Compute the function's integral within the specified limits using the Simpson rule.
  210.      *
  211.      * @param funcR1ToR1 R1ToR1 Function
  212.      * @param dblLeft Left Variate
  213.      * @param dblRight Right Variate
  214.      *
  215.      * @return The Integral
  216.      *
  217.      * @throws java.lang.Exception Thrown if the error cannot be computed
  218.      */

  219.     public static final double Simpson (
  220.         final org.drip.function.definition.R1ToR1 funcR1ToR1,
  221.         final double dblLeft,
  222.         final double dblRight)
  223.         throws java.lang.Exception
  224.     {
  225.         if (null == funcR1ToR1 || !org.drip.numerical.common.NumberUtil.IsValid (dblLeft) ||
  226.             !org.drip.numerical.common.NumberUtil.IsValid (dblRight) || dblLeft > dblRight)
  227.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson => Invalid Inputs");

  228.         if (dblLeft == dblRight) return 0.;

  229.         double dblYLeft = funcR1ToR1.evaluate (dblLeft);

  230.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblYLeft))
  231.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson => Cannot calculate Y at " + dblLeft);

  232.         double dblXMid = 0.5 * (dblLeft + dblRight);

  233.         double dblYMid = funcR1ToR1.evaluate (dblXMid);

  234.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblYMid))
  235.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson => Cannot calculate Y at " + dblXMid);

  236.         double dblYRight = funcR1ToR1.evaluate (dblRight);

  237.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblYRight))
  238.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson => Cannot calculate Y at " + dblRight);

  239.         return (dblRight - dblLeft) / 6. * (dblYLeft + 4. * dblYMid + dblYRight);
  240.     }

  241.     /**
  242.      * Compute the function's integral within the specified limits using the Simpson 3/8 rule.
  243.      *
  244.      * @param funcR1ToR1 R1ToR1 Function
  245.      * @param dblLeft Left Variate
  246.      * @param dblRight Right Variate
  247.      *
  248.      * @return The Integral
  249.      *
  250.      * @throws java.lang.Exception Thrown if the error cannot be computed
  251.      */

  252.     public static final double Simpson38 (
  253.         final org.drip.function.definition.R1ToR1 funcR1ToR1,
  254.         final double dblLeft,
  255.         final double dblRight)
  256.         throws java.lang.Exception
  257.     {
  258.         if (null == funcR1ToR1 || !org.drip.numerical.common.NumberUtil.IsValid (dblLeft) ||
  259.             !org.drip.numerical.common.NumberUtil.IsValid (dblRight) || dblLeft > dblRight)
  260.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson38 => Invalid Inputs");

  261.         if (dblLeft == dblRight) return 0.;

  262.         double dblY0 = funcR1ToR1.evaluate (dblLeft);

  263.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY0))
  264.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson38 => Cannot calculate Y at " +
  265.                 dblLeft);

  266.         double dblX1 = (2. * dblLeft + dblRight) / 3.;

  267.         double dblY1 = funcR1ToR1.evaluate (dblX1);

  268.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY1))
  269.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson38 => Cannot calculate Y at " + dblX1);

  270.         double dblX2 = (dblLeft + 2. * dblRight) / 3.;

  271.         double dblY2 = funcR1ToR1.evaluate (dblX2);

  272.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY2))
  273.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson38 => Cannot calculate Y at " + dblX2);

  274.         double dblY3 = funcR1ToR1.evaluate (dblRight);

  275.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY3))
  276.             throw new java.lang.Exception ("R1ToR1Integrator::Simpson38 => Cannot calculate Y at " +
  277.                 dblRight);

  278.         return (dblRight - dblLeft) * (0.125 * dblY0 + 0.375 * dblY1 + 0.375 * dblY2 + 0.125 * dblY3);
  279.     }

  280.     /**
  281.      * Compute the function's integral within the specified limits using the Boole rule.
  282.      *
  283.      * @param funcR1ToR1 R1ToR1 Function
  284.      * @param dblLeft Left Variate
  285.      * @param dblRight Right Variate
  286.      *
  287.      * @return The Integral
  288.      *
  289.      * @throws java.lang.Exception Thrown if the error cannot be computed
  290.      */

  291.     public static final double Boole (
  292.         final org.drip.function.definition.R1ToR1 funcR1ToR1,
  293.         final double dblLeft,
  294.         final double dblRight)
  295.         throws java.lang.Exception
  296.     {
  297.         if (null == funcR1ToR1 || !org.drip.numerical.common.NumberUtil.IsValid (dblLeft) ||
  298.             !org.drip.numerical.common.NumberUtil.IsValid (dblRight) || dblLeft > dblRight)
  299.             throw new java.lang.Exception ("R1ToR1Integrator::Boole => Invalid Inputs");

  300.         if (dblLeft == dblRight) return 0.;

  301.         double dblY0 = funcR1ToR1.evaluate (dblLeft);

  302.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY0))
  303.             throw new java.lang.Exception ("R1ToR1Integrator::Boole => Cannot calculate Y at " + dblLeft);

  304.         double dblX1 = 0.25 * dblLeft + 0.75 * dblRight;

  305.         double dblY1 = funcR1ToR1.evaluate (dblX1);

  306.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY1))
  307.             throw new java.lang.Exception ("R1ToR1Integrator::Boole => Cannot calculate Y at " + dblX1);

  308.         double dblX2 = 0.5 * (dblLeft + dblRight);

  309.         double dblY2 = funcR1ToR1.evaluate (dblX2);

  310.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY2))
  311.             throw new java.lang.Exception ("R1ToR1Integrator::Boole => Cannot calculate Y at " + dblX2);

  312.         double dblX3 = 0.75 * dblLeft + 0.25 * dblRight;

  313.         double dblY3 = funcR1ToR1.evaluate (dblX3);

  314.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY3))
  315.             throw new java.lang.Exception ("R1ToR1Integrator::Boole => Cannot calculate Y at " + dblX3);

  316.         double dblY4 = funcR1ToR1.evaluate (dblRight);

  317.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblY4))
  318.             throw new java.lang.Exception ("R1ToR1Integrator::Boole => Cannot calculate Y at " + dblRight);

  319.         return (dblRight - dblLeft) / 90 * (7 * dblY0 + 32 * dblY1 + 12 * dblY2 + 32 * dblY3 + 7 * dblY4);
  320.     }

  321.     /**
  322.      * Integrate Numerically over [-infinity, +infinity] using a Change of Variables
  323.      *
  324.      * @param funcR1ToR1 The R1ToR1 Function
  325.      *
  326.      * @return The Numerical Integrand
  327.      *
  328.      * @throws java.lang.Exception Thrown if the Integral cannot be computed
  329.      */

  330.     public static final double LeftInfiniteRightInfinite (
  331.         final org.drip.function.definition.R1ToR1 funcR1ToR1)
  332.         throws java.lang.Exception
  333.     {
  334.         if (null == funcR1ToR1)
  335.             throw new java.lang.Exception ("R1ToR1Integrator::LeftInfiniteRightInfinite => Invalid Inputs");

  336.         org.drip.function.definition.R1ToR1 auTransformed = new
  337.             org.drip.function.definition.R1ToR1 (null) {
  338.             @Override public double evaluate (
  339.                 final double dblX)
  340.                 throws java.lang.Exception
  341.             {
  342.                 if (!org.drip.numerical.common.NumberUtil.IsValid (dblX))
  343.                     throw new java.lang.Exception
  344.                         ("IntegratorR1ToR1::LeftInfiniteRightInfinite => Invalid Inputs");

  345.                 double dblX2 = dblX * dblX;
  346.                 double dblXTransform = 1. / (1. - dblX2);

  347.                 return (1. + dblX2) / (dblXTransform * dblXTransform) * funcR1ToR1.evaluate (dblX /
  348.                     dblXTransform);
  349.             }
  350.         };

  351.         return auTransformed.integrate (-1., +1.);
  352.     }

  353.     /**
  354.      * Integrate the specified Function Numerically from -infinity to the specified Right Limit
  355.      *
  356.      * @param funcR1ToR1 The Input R1ToR1 Function
  357.      * @param dblRight The Right Integration Limit
  358.      *
  359.      * @return The Results of the Integration
  360.      *
  361.      * @throws java.lang.Exception Thrown if the Integrand cannot be evaluated
  362.      */

  363.     public static final double LeftInfinite (
  364.         final org.drip.function.definition.R1ToR1 funcR1ToR1,
  365.         final double dblRight)
  366.         throws java.lang.Exception
  367.     {
  368.         if (null == funcR1ToR1 || !org.drip.numerical.common.NumberUtil.IsValid (dblRight))
  369.             throw new java.lang.Exception ("R1ToR1Integrator::LeftInfinite => Invalid Inputs");

  370.         org.drip.function.definition.R1ToR1 auTransformed = new
  371.             org.drip.function.definition.R1ToR1 (null) {
  372.             @Override public double evaluate (
  373.                 final double dblX)
  374.                 throws java.lang.Exception
  375.             {
  376.                 if (!org.drip.numerical.common.NumberUtil.IsValid (dblX))
  377.                     throw new java.lang.Exception ("IntegratorR1ToR1::LeftInfinite => Invalid Inputs");

  378.                 return (funcR1ToR1.evaluate (dblRight - ((1. - dblX) / dblX))) / (dblX * dblX);
  379.             }
  380.         };

  381.         return auTransformed.integrate (0., +1.);
  382.     }

  383.     /**
  384.      * Integrate the specified Function Numerically from the specified Left Limit to +infinity
  385.      *
  386.      * @param funcR1ToR1 The Input R1ToR1 Function
  387.      * @param dblLeft The Left Integration Limit
  388.      *
  389.      * @return The Results of the Integration
  390.      *
  391.      * @throws java.lang.Exception Thrown if the Integrand cannot be evaluated
  392.      */

  393.     public static final double RightInfinite (
  394.         final org.drip.function.definition.R1ToR1 funcR1ToR1,
  395.         final double dblLeft)
  396.         throws java.lang.Exception
  397.     {
  398.         if (null == funcR1ToR1 || !org.drip.numerical.common.NumberUtil.IsValid (dblLeft))
  399.             throw new java.lang.Exception ("R1ToR1Integrator::RightInfinite => Invalid Inputs");

  400.         org.drip.function.definition.R1ToR1 auTransformed = new
  401.             org.drip.function.definition.R1ToR1 (null) {
  402.             @Override public double evaluate (
  403.                 final double dblX)
  404.                 throws java.lang.Exception
  405.             {
  406.                 if (!org.drip.numerical.common.NumberUtil.IsValid (dblX))
  407.                     throw new java.lang.Exception ("R1ToR1Integrator::RightInfinite => Invalid Inputs");

  408.                 double dblXInversion = 1. - dblX;

  409.                 return (funcR1ToR1.evaluate (dblLeft + (dblX / dblXInversion))) / (dblXInversion *
  410.                     dblXInversion);
  411.             }
  412.         };

  413.         return auTransformed.integrate (0., +1.);
  414.     }
  415. }