AkimaLocalC1Generator.java

  1. package org.drip.spline.pchip;

  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>AkimaLocalC1Generator</i> generates the local control C1 Slope using the Akima Cubic Algorithm.
  82.  *
  83.  * <br><br>
  84.  *  <ul>
  85.  *      <li>
  86.  *          Akima (1970): A New Method of Interpolation and Smooth Curve Fitting based on Local Procedures
  87.  *              <i>Journal of the Association for the Computing Machinery</i> <b>17 (4)</b> 589-602
  88.  *      </li>
  89.  *  </ul>
  90.  *
  91.  * <br><br>
  92.  *  <ul>
  93.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ComputationalCore.md">Computational Core Module</a></li>
  94.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/SplineBuilderLibrary.md">Spline Builder Library</a></li>
  95.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/spline/README.md">Basis Splines and Linear Compounders across a Broad Family of Spline Basis Functions</a></li>
  96.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/spline/pchip/README.md">Monotone Convex Themed PCHIP Splines</a></li>
  97.  *  </ul>
  98.  * <br><br>
  99.  *
  100.  * @author Lakshmi Krishnamurthy
  101.  */

  102. public class AkimaLocalC1Generator {
  103.     private double[] _adblResponseValue = null;
  104.     private double[] _adblPredictorOrdinate = null;
  105.     private double[] _adblExtendedResponseValue = null;
  106.     private double[] _adblExtendedPredictorOrdinate = null;

  107.     /**
  108.      * Construct an Instance of AkimaLocalC1Generator from the Array of the supplied Predictor Ordinates
  109.      *  and the Response Values
  110.      *  
  111.      * @param adblPredictorOrdinate Array of the Predictor Ordinates
  112.      * @param adblResponseValue Array of the Response Values
  113.      *
  114.      * @return Instance of AkimaLocalC1Generator
  115.      */

  116.     public static final AkimaLocalC1Generator Create (
  117.         final double[] adblPredictorOrdinate,
  118.         final double[] adblResponseValue)
  119.     {
  120.         AkimaLocalC1Generator alcr = null;

  121.         try {
  122.             alcr = new AkimaLocalC1Generator (adblPredictorOrdinate, adblResponseValue);
  123.         } catch (java.lang.Exception e) {
  124.             e.printStackTrace();

  125.             return null;
  126.         }

  127.         return alcr.extendPredictorOrdinate() && alcr.extendResponseValue() ? alcr : null;
  128.     }

  129.     private AkimaLocalC1Generator (
  130.         final double[] adblPredictorOrdinate,
  131.         final double[] adblResponseValue)
  132.         throws java.lang.Exception
  133.     {
  134.         if (null == (_adblPredictorOrdinate = adblPredictorOrdinate) || null == (_adblResponseValue =
  135.             adblResponseValue))
  136.             throw new java.lang.Exception ("AkimaLocalC1Generator ctr: Invalid Inputs");

  137.         int iNumPredictorOrdinate = _adblPredictorOrdinate.length;

  138.         if (2 >= iNumPredictorOrdinate || iNumPredictorOrdinate != _adblResponseValue.length)
  139.             throw new java.lang.Exception ("AkimaLocalC1Generator ctr: Invalid Inputs");
  140.     }

  141.     private boolean extendPredictorOrdinate()
  142.     {
  143.         int iNumPredictorOrdinate = _adblPredictorOrdinate.length;
  144.         int iNumExtendedPredictorOrdinate = iNumPredictorOrdinate + 4;
  145.         _adblExtendedPredictorOrdinate = new double[iNumExtendedPredictorOrdinate];

  146.         for (int i = 0; i < iNumExtendedPredictorOrdinate; ++i) {
  147.             if (2 <= i && iNumExtendedPredictorOrdinate - 3 >= i)
  148.                 _adblExtendedPredictorOrdinate[i] = _adblPredictorOrdinate[i - 2];
  149.         }

  150.         double dblSkippedLeftPredictorWidth = _adblPredictorOrdinate[2] - _adblPredictorOrdinate[0];
  151.         _adblExtendedPredictorOrdinate[0] = _adblPredictorOrdinate[0] - dblSkippedLeftPredictorWidth;
  152.         _adblExtendedPredictorOrdinate[1] = _adblPredictorOrdinate[1] - dblSkippedLeftPredictorWidth;
  153.         double dblSkippedRightPredictorWidth = _adblPredictorOrdinate[iNumPredictorOrdinate - 1] -
  154.             _adblPredictorOrdinate[iNumPredictorOrdinate - 3];
  155.         _adblExtendedPredictorOrdinate[iNumExtendedPredictorOrdinate - 2] =
  156.             _adblPredictorOrdinate[iNumPredictorOrdinate - 2] + dblSkippedRightPredictorWidth;
  157.         _adblExtendedPredictorOrdinate[iNumExtendedPredictorOrdinate - 1] =
  158.             _adblPredictorOrdinate[iNumPredictorOrdinate - 1] + dblSkippedRightPredictorWidth;
  159.         return true;
  160.     }

  161.     private boolean setExtendedResponseValue (
  162.         final int i,
  163.         final boolean bRight)
  164.     {
  165.         if (bRight) {
  166.             _adblExtendedResponseValue[i] = 2. * (_adblExtendedResponseValue[i - 1] -
  167.                 _adblExtendedResponseValue[i - 2]) / (_adblExtendedPredictorOrdinate[i - 1] -
  168.                     _adblExtendedPredictorOrdinate[i - 2]) - ((_adblExtendedResponseValue[i - 2] -
  169.                         _adblExtendedResponseValue[i - 3]) / (_adblExtendedPredictorOrdinate[i - 2] -
  170.                             _adblExtendedPredictorOrdinate[i - 3]));
  171.             _adblExtendedResponseValue[i] = _adblExtendedResponseValue[i] * (_adblExtendedResponseValue[i] -
  172.                 _adblExtendedResponseValue[i - 1]) + _adblExtendedResponseValue[i - 1];
  173.         } else {
  174.             _adblExtendedResponseValue[i] = 2. * (_adblExtendedResponseValue[i + 2] -
  175.                 _adblExtendedResponseValue[i + 1]) / (_adblExtendedPredictorOrdinate[i + 2] -
  176.                     _adblExtendedPredictorOrdinate[i + 1]) - ((_adblExtendedResponseValue[i + 3] -
  177.                         _adblExtendedResponseValue[i + 2]) / (_adblExtendedPredictorOrdinate[i + 3] -
  178.                             _adblExtendedPredictorOrdinate[i + 2]));
  179.             _adblExtendedResponseValue[i] = _adblExtendedResponseValue[i + 1] - _adblExtendedResponseValue[i]
  180.                 * (_adblExtendedResponseValue[i + 1] - _adblExtendedResponseValue[i]);
  181.         }

  182.         return true;
  183.     }

  184.     private boolean extendResponseValue()
  185.     {
  186.         int iNumResponseValue = _adblResponseValue.length;
  187.         int iNumExtendedResponseValue = iNumResponseValue + 4;
  188.         _adblExtendedResponseValue = new double[iNumExtendedResponseValue];

  189.         for (int i = 0; i < iNumExtendedResponseValue; ++i) {
  190.             if (2 <= i && iNumExtendedResponseValue - 3 >= i)
  191.                 _adblExtendedResponseValue[i] = _adblResponseValue[i - 2];
  192.         }

  193.         return setExtendedResponseValue (1, false) && setExtendedResponseValue (0, false) &&
  194.             setExtendedResponseValue (iNumExtendedResponseValue - 2, true) && setExtendedResponseValue
  195.                 (iNumExtendedResponseValue - 1, true) ? true : false;
  196.     }

  197.     public double[] C1()
  198.     {
  199.         int iNumPredictorOrdinate = _adblPredictorOrdinate.length;
  200.         double[] adblC1 = new double[iNumPredictorOrdinate];
  201.         double[] adblExtendedSlope = new double[iNumPredictorOrdinate + 3];

  202.         for (int i = 0; i < iNumPredictorOrdinate + 3; ++i)
  203.             adblExtendedSlope[i] = (_adblExtendedResponseValue[i + 1] - _adblExtendedResponseValue[i]) /
  204.                 (_adblExtendedPredictorOrdinate[i + 1] - _adblExtendedPredictorOrdinate[i]);

  205.         for (int i = 0; i < iNumPredictorOrdinate; ++i) {
  206.             double dblSlope10 = java.lang.Math.abs (adblExtendedSlope[i + 1] - adblExtendedSlope[i]);

  207.             double dblSlope32 = java.lang.Math.abs (adblExtendedSlope[i + 3] - adblExtendedSlope[i + 2]);

  208.             if (0. == dblSlope10 && 0. == dblSlope32)
  209.                 adblC1[i] = 0.5 * (adblExtendedSlope[i + 1] + adblExtendedSlope[i + 2]);
  210.             else
  211.                 adblC1[i] = (dblSlope32 * adblExtendedSlope[i + 1] + dblSlope10 * adblExtendedSlope[i + 2]) /
  212.                     (dblSlope10 + dblSlope32);
  213.         }

  214.         return adblC1;
  215.     }
  216. }