Square.java

  1. package org.drip.function.matrix;

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

  5. /*!
  6.  * Copyright (C) 2019 Lakshmi Krishnamurthy
  7.  *
  8.  *  This file is part of DROP, an open-source library targeting risk, transaction costs, exposure, margin
  9.  *      calculations, valuation adjustment, and portfolio construction within and across fixed income,
  10.  *      credit, commodity, equity, FX, and structured products.
  11.  *  
  12.  *      https://lakshmidrip.github.io/DROP/
  13.  *  
  14.  *  DROP is composed of three modules:
  15.  *  
  16.  *  - DROP Analytics Core - https://lakshmidrip.github.io/DROP-Analytics-Core/
  17.  *  - DROP Portfolio Core - https://lakshmidrip.github.io/DROP-Portfolio-Core/
  18.  *  - DROP Numerical Core - https://lakshmidrip.github.io/DROP-Numerical-Core/
  19.  *
  20.  *  DROP Analytics Core implements libraries for the following:
  21.  *  - Fixed Income Analytics
  22.  *  - Asset Backed Analytics
  23.  *  - XVA Analytics
  24.  *  - Exposure and Margin Analytics
  25.  *
  26.  *  DROP Portfolio Core implements libraries for the following:
  27.  *  - Asset Allocation Analytics
  28.  *  - Transaction Cost Analytics
  29.  *
  30.  *  DROP Numerical Core implements libraries for the following:
  31.  *  - Statistical Learning
  32.  *  - Numerical Optimizer
  33.  *  - Spline Builder
  34.  *  - Algorithm Support
  35.  *
  36.  *  Documentation for DROP is Spread Over:
  37.  *
  38.  *  - Main                     => https://lakshmidrip.github.io/DROP/
  39.  *  - Wiki                     => https://github.com/lakshmiDRIP/DROP/wiki
  40.  *  - GitHub                   => https://github.com/lakshmiDRIP/DROP
  41.  *  - Repo Layout Taxonomy     => https://github.com/lakshmiDRIP/DROP/blob/master/Taxonomy.md
  42.  *  - Javadoc                  => https://lakshmidrip.github.io/DROP/Javadoc/index.html
  43.  *  - Technical Specifications => https://github.com/lakshmiDRIP/DROP/tree/master/Docs/Internal
  44.  *  - Release Versions         => https://lakshmidrip.github.io/DROP/version.html
  45.  *  - Community Credits        => https://lakshmidrip.github.io/DROP/credits.html
  46.  *  - Issues Catalog           => https://github.com/lakshmiDRIP/DROP/issues
  47.  *  - JUnit                    => https://lakshmidrip.github.io/DROP/junit/index.html
  48.  *  - Jacoco                   => https://lakshmidrip.github.io/DROP/jacoco/index.html
  49.  *
  50.  *  Licensed under the Apache License, Version 2.0 (the "License");
  51.  *      you may not use this file except in compliance with the License.
  52.  *  
  53.  *  You may obtain a copy of the License at
  54.  *      http://www.apache.org/licenses/LICENSE-2.0
  55.  *  
  56.  *  Unless required by applicable law or agreed to in writing, software
  57.  *      distributed under the License is distributed on an "AS IS" BASIS,
  58.  *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  59.  *  
  60.  *  See the License for the specific language governing permissions and
  61.  *      limitations under the License.
  62.  */

  63. /**
  64.  * <i>Square</i> implements a Square Matrix. The References are:
  65.  *  
  66.  * <br><br>
  67.  *  <ul>
  68.  *      <li>
  69.  *          Claerbout, J. F. (1985): <i>Fundamentals of Geo-physical Data Processing</i> <b>Blackwell
  70.  *              Scientific</b>
  71.  *      </li>
  72.  *      <li>
  73.  *          Horn, R. A., and C. R. Johnson (1991): <i>Topics in Matrix Analysis</i> <b>Cambridge University
  74.  *              Press</b>
  75.  *      </li>
  76.  *      <li>
  77.  *          Schwerdtfeger, A. (1938): <i>Les Fonctions de Matrices: Les Fonctions Univalentes I</i>
  78.  *              <b>Hermann</b> Paris, France
  79.  *      </li>
  80.  *      <li>
  81.  *          Sylvester, J. J. (1883): On the Equation to the Secular Inequalities in the Planetary Theory
  82.  *              <i>The London, Edinburgh, and Dublin Philosophical Magazine and Journal of Science</i> <b>16
  83.  *              (100)</b> 267-269
  84.  *      </li>
  85.  *      <li>
  86.  *          Wikipedia (2019): Sylvester Formula https://en.wikipedia.org/wiki/Sylvester%27s_formula
  87.  *      </li>
  88.  *  </ul>
  89.  *  
  90.  * <br><br>
  91.  *  <ul>
  92.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/NumericalCore.md">Numerical Core Module</a></li>
  93.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/NumericalSupportLibrary.md">Numerical Support Library</a></li>
  94.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/sample/README.md">Sample</a></li>
  95.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/sample/matrix/README.md">Linear Algebra and Matrix Utilities</a></li>
  96.  *  </ul>
  97.  * <br><br>
  98.  *
  99.  * @author Lakshmi Krishnamurthy
  100.  */

  101. public class Square
  102. {
  103.     public double[][] _grid = null;

  104.     /**
  105.      * Square Constructor
  106.      *
  107.      * @param grid Grid of Elements
  108.      *
  109.      * @throws java.lang.Exception Throwjn if the Inputs are Invalid
  110.      */

  111.     public Square (
  112.         final double[][] grid)
  113.         throws java.lang.Exception
  114.     {
  115.         if (null == (_grid = grid))
  116.         {
  117.             throw new java.lang.Exception (
  118.                 "Square Constructor => Invalid Inputs"
  119.             );
  120.         }

  121.         int dimension = _grid.length;

  122.         if (0 == dimension)
  123.         {
  124.             throw new java.lang.Exception (
  125.                 "Square Constructor => Invalid Inputs"
  126.             );
  127.         }

  128.         for (int dimensionIndex = 0;
  129.             dimensionIndex < dimension;
  130.             ++dimensionIndex)
  131.         {
  132.             if (null == _grid[dimensionIndex] ||
  133.                 dimension != _grid[dimensionIndex].length ||
  134.                 !org.drip.numerical.common.NumberUtil.IsValid (
  135.                     _grid[dimensionIndex]
  136.                 )
  137.             )
  138.             {
  139.                 throw new java.lang.Exception (
  140.                     "Square Constructor => Invalid Inputs"
  141.                 );
  142.             }
  143.         }
  144.     }

  145.     /**
  146.      * Retrieve the Grid of Elements
  147.      *
  148.      * @return Grid of Elements
  149.      */

  150.     public double[][] grid()
  151.     {
  152.         return _grid;
  153.     }

  154.     /**
  155.      * Retrieve the Dimension of the Square Matrix
  156.      *
  157.      * @return Dimension of the Square Matrix
  158.      */

  159.     public int dimension()
  160.     {
  161.         return _grid.length;
  162.     }

  163.     /**
  164.      * Retrieve the Eigen-Components of the Square Matrix
  165.      *
  166.      * @return The Eigen-Components of the Square Matrix
  167.      */

  168.     public org.drip.numerical.eigen.EigenOutput eigenize()
  169.     {
  170.         try
  171.         {
  172.             return new org.drip.numerical.eigen.QREigenComponentExtractor (
  173.                 100,
  174.                 1.e-06
  175.             ).eigenize (
  176.                 _grid
  177.             );
  178.         }
  179.         catch (java.lang.Exception e)
  180.         {
  181.             e.printStackTrace();
  182.         }

  183.         return null;
  184.     }

  185.     /**
  186.      * Generate the Frobenius Covariance
  187.      *
  188.      * @return The Frobenius Covariance
  189.      */

  190.     public org.drip.function.matrix.FrobeniusCovariance frobeniusCovariance()
  191.     {
  192.         org.drip.function.matrix.FrobeniusCovariance frobeniusCovariance =
  193.             new org.drip.function.matrix.FrobeniusCovariance();

  194.         org.drip.numerical.eigen.EigenOutput eigenOutput = eigenize();

  195.         if (null == eigenOutput)
  196.         {
  197.             return null;
  198.         }

  199.         double[] eigenValueArray = eigenOutput.eigenValueArray();

  200.         int dimension = _grid.length;
  201.         double[][][] eigenShadowArray = new double[dimension][dimension][dimension];

  202.         for (int eigenIndex = 0;
  203.             eigenIndex < dimension;
  204.             ++eigenIndex)
  205.         {
  206.             for (int dimensionIndexI = 0;
  207.                 dimensionIndexI < dimension;
  208.                 ++dimensionIndexI)
  209.             {
  210.                 for (int dimensionIndexJ = 0;
  211.                     dimensionIndexJ < dimension;
  212.                     ++dimensionIndexJ)
  213.                 {
  214.                     eigenShadowArray[eigenIndex][dimensionIndexI][dimensionIndexJ] =
  215.                         _grid[dimensionIndexI][dimensionIndexJ] - (
  216.                             dimensionIndexI == dimensionIndexJ ? eigenValueArray[eigenIndex] : 0.
  217.                         );
  218.                 }
  219.             }
  220.         }

  221.         for (int componentIndex = 0;
  222.             componentIndex < dimension;
  223.             ++componentIndex)
  224.         {
  225.             double[][] frobeniusComponentMatrix = null;
  226.             double componentEigenValue = eigenValueArray[componentIndex];

  227.             for (int eigenIndex = 0;
  228.                 eigenIndex < dimension;
  229.                 ++eigenIndex)
  230.             {
  231.                 if (eigenIndex == componentIndex)
  232.                 {
  233.                     continue;
  234.                 }

  235.                 if (null == frobeniusComponentMatrix)
  236.                 {
  237.                     frobeniusComponentMatrix = org.drip.numerical.linearalgebra.Matrix.Scale2D (
  238.                         eigenShadowArray[eigenIndex],
  239.                         1. / (componentEigenValue - eigenValueArray[eigenIndex])
  240.                     );
  241.                 }
  242.                 else
  243.                 {
  244.                     frobeniusComponentMatrix = org.drip.numerical.linearalgebra.Matrix.Scale2D (
  245.                         org.drip.numerical.linearalgebra.Matrix.Product (
  246.                             frobeniusComponentMatrix,
  247.                             eigenShadowArray[eigenIndex]
  248.                         ),
  249.                         1. / (componentEigenValue - eigenValueArray[eigenIndex])
  250.                     );
  251.                 }
  252.             }

  253.             try
  254.             {
  255.                 if (!frobeniusCovariance.addComponent (
  256.                     componentEigenValue,
  257.                     new org.drip.function.matrix.Square (
  258.                         frobeniusComponentMatrix
  259.                     )
  260.                 ))
  261.                 {
  262.                     return null;
  263.                 }
  264.             }
  265.             catch (java.lang.Exception e)
  266.             {
  267.                 e.printStackTrace();
  268.             }
  269.         }

  270.         return frobeniusCovariance;
  271.     }

  272.     /**
  273.      * Compute the Value of the Matrix using the specified Function
  274.      *
  275.      * @param r1ToR1Function The R<sup>1</sup> To R<sup>1</sup> Function
  276.      *
  277.      * @return The Function Matrix Value
  278.      */

  279.     public double[][] evaluate (
  280.         final org.drip.function.definition.R1ToR1 r1ToR1Function)
  281.     {
  282.         if (null == r1ToR1Function)
  283.         {
  284.             return null;
  285.         }

  286.         int dimension = _grid.length;
  287.         double[][] matrixFunction = null;

  288.         org.drip.function.matrix.FrobeniusCovariance frobeniusCovariance = frobeniusCovariance();

  289.         if (null == frobeniusCovariance)
  290.         {
  291.             return null;
  292.         }

  293.         for (java.util.Map.Entry<java.lang.Double, org.drip.function.matrix.Square> componentMapEntry :
  294.             frobeniusCovariance.componentMap().entrySet())
  295.         {
  296.             double[][] frobeniusComponentFunctionProjection = null;

  297.             try
  298.             {
  299.                 frobeniusComponentFunctionProjection = org.drip.numerical.linearalgebra.Matrix.Scale2D (
  300.                     componentMapEntry.getValue().grid(),
  301.                     r1ToR1Function.evaluate (
  302.                         componentMapEntry.getKey()
  303.                     )
  304.                 );
  305.             }
  306.             catch (java.lang.Exception e)
  307.             {
  308.                 e.printStackTrace();

  309.                 return null;
  310.             }

  311.             if (null == frobeniusComponentFunctionProjection)
  312.             {
  313.                 return null;
  314.             }

  315.             if (null == matrixFunction)
  316.             {
  317.                 matrixFunction = frobeniusComponentFunctionProjection;
  318.             }
  319.             else
  320.             {
  321.                 for (int dimensionIndexI = 0;
  322.                     dimensionIndexI < dimension;
  323.                     ++dimensionIndexI)
  324.                 {
  325.                     for (int dimensionIndexJ = 0;
  326.                         dimensionIndexJ < dimension;
  327.                         ++dimensionIndexJ)
  328.                     {
  329.                         matrixFunction[dimensionIndexI][dimensionIndexJ] =
  330.                             matrixFunction[dimensionIndexI][dimensionIndexJ] +
  331.                             frobeniusComponentFunctionProjection[dimensionIndexI][dimensionIndexJ];
  332.                     }
  333.                 }
  334.             }
  335.         }

  336.         return matrixFunction;
  337.     }

  338.     /**
  339.      * Compute the Determinant
  340.      *
  341.      * @return The Determinant
  342.      */

  343.     public double determinant()
  344.     {
  345.         org.drip.numerical.eigen.EigenOutput eigenOutput = eigenize();

  346.         if (null == eigenOutput)
  347.         {
  348.             return 0.;
  349.         }

  350.         double[] eigenValueArray = eigenOutput.eigenValueArray();

  351.         double determinant = 1.;
  352.         int dimension = _grid.length;

  353.         for (int eigenIndex = 0;
  354.             eigenIndex < dimension;
  355.             ++eigenIndex)
  356.         {
  357.              determinant = determinant * eigenValueArray[eigenIndex];
  358.         }

  359.         return determinant;
  360.     }
  361. }