Matrix.java

  1. package org.drip.numerical.linearalgebra;

  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>Matrix</i> implements Matrix manipulation routines. It exports the following functionality:
  82.  *  <ul>
  83.  *      <li>
  84.  *          Matrix Inversion using Closed form solutions (for low-dimension matrices), or using Gaussian
  85.  *              elimination
  86.  *      </li>
  87.  *      <li>
  88.  *          Matrix Product
  89.  *      </li>
  90.  *      <li>
  91.  *          Matrix Diagonalization and Diagonal Pivoting
  92.  *      </li>
  93.  *      <li>
  94.  *          Matrix Regularization through Row Addition/Row Swap
  95.  *      </li>
  96.  *  </ul>
  97.  *
  98.  * <br><br>
  99.  *  <ul>
  100.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ComputationalCore.md">Computational Core Module</a></li>
  101.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/NumericalAnalysisLibrary.md">Numerical Analysis Library</a></li>
  102.  *      <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>
  103.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/numerical/linearalgebra/README.md">Linear Algebra Matrix Transform Library</a></li>
  104.  *  </ul>
  105.  * <br><br>
  106.  *
  107.  * @author Lakshmi Krishnamurthy
  108.  */

  109. public class Matrix {

  110.     /**
  111.      * Lower Triangular Matrix
  112.      */

  113.     public static int LOWER_TRIANGULAR = 1;

  114.     /**
  115.      * Upper Triangular Matrix
  116.      */

  117.     public static int UPPER_TRIANGULAR = 2;

  118.     /**
  119.      * Lower+Upper Triangular Matrix
  120.      */

  121.     public static int LOWER_AND_UPPER_TRIANGULAR = 3;

  122.     /**
  123.      * Non Triangular Matrix
  124.      */

  125.     public static int NON_TRIANGULAR = 0;

  126.     /**
  127.      * Diagonalize the specified row in the source matrix, and apply comparable operations to the target
  128.      *
  129.      * @param iQ Row in the Source Matrix
  130.      * @param aadblZ2XJack Source Matrix
  131.      * @param aadblZ2YJack Target Matrix
  132.      *
  133.      * @return TRUE - Diagonalization was successful
  134.      */

  135.     public static final boolean DiagonalizeRow (
  136.         final int iQ,
  137.         final double[][] aadblZ2XJack,
  138.         final double[][] aadblZ2YJack)
  139.     {
  140.         if (0. != aadblZ2XJack[iQ][iQ]) return true;

  141.         int iSize = aadblZ2XJack.length;
  142.         int iP = iSize - 1;

  143.         while (0. == aadblZ2XJack[iP][iQ] && iP >= 0) --iP;

  144.         if (0 > iP) return false;

  145.         for (int j = 0; j < iSize; ++j)
  146.             aadblZ2XJack[iQ][j] += aadblZ2XJack[iP][j];

  147.         aadblZ2YJack[iQ][iP] += 1.;
  148.         return true;
  149.     }

  150.     /**
  151.      * Compute the Product of an Input Matrix and a Column
  152.      *
  153.      * @param aadblA Matrix A
  154.      * @param adblB Array B
  155.      *
  156.      * @return The Product
  157.      */

  158.     public static final double[] Product (
  159.         final double[][] aadblA,
  160.         final double[] adblB)
  161.     {
  162.         if (null == aadblA || null == adblB) return null;

  163.         int iNumACol = aadblA[0].length;
  164.         int iNumProductCol = adblB.length;
  165.         int iNumProductRow = aadblA.length;
  166.         double[] adblProduct = new double[iNumProductRow];

  167.         if (0 == iNumACol || iNumACol != adblB.length || 0 == iNumProductRow || 0 == iNumProductCol)
  168.             return null;

  169.         for (int iRow = 0; iRow < iNumProductRow; ++iRow) {
  170.             adblProduct[iRow] = 0.;

  171.             for (int i = 0; i < iNumACol; ++i) {
  172.                 if (!org.drip.numerical.common.NumberUtil.IsValid (aadblA[iRow][i]) ||
  173.                     !org.drip.numerical.common.NumberUtil.IsValid (adblB[i]))
  174.                     return null;

  175.                 adblProduct[iRow] += aadblA[iRow][i] * adblB[i];
  176.             }
  177.         }

  178.         return adblProduct;
  179.     }

  180.     /**
  181.      * Compute the Product of an input column and a matrix
  182.      *
  183.      * @param adblA Column A
  184.      * @param aadblB Matrix B
  185.      *
  186.      * @return The Product
  187.      */

  188.     public static final double[][] Product (
  189.         final double[] adblA,
  190.         final double[][] aadblB)
  191.     {
  192.         if (null == adblA || null == aadblB) return null;

  193.         int iNumACol = adblA.length;
  194.         int iNumProductCol = aadblB.length;
  195.         double[][] aadblProduct = new double[iNumACol][iNumProductCol];

  196.         if (0 == iNumACol || iNumACol != aadblB.length || 0 == iNumProductCol) return null;

  197.         for (int iRow = 0; iRow < iNumACol; ++iRow) {
  198.             for (int iCol = 0; iCol < iNumProductCol; ++iCol) {
  199.                 aadblProduct[iRow][iCol] = 0.;

  200.                 for (int i = 0; i < iNumACol; ++i) {
  201.                     if (!org.drip.numerical.common.NumberUtil.IsValid (adblA[iRow]) ||
  202.                         !org.drip.numerical.common.NumberUtil.IsValid (aadblB[i][iCol]))
  203.                         return null;

  204.                     aadblProduct[iRow][iCol] += adblA[iRow] * aadblB[i][iCol];
  205.                 }
  206.             }
  207.         }

  208.         return aadblProduct;
  209.     }

  210.     /**
  211.      * Compute the Product of the input matrices
  212.      *
  213.      * @param aadblA Matrix A
  214.      * @param aadblB Matrix B
  215.      *
  216.      * @return The Product
  217.      */

  218.     public static final double[][] Product (
  219.         final double[][] aadblA,
  220.         final double[][] aadblB)
  221.     {
  222.         if (null == aadblA || null == aadblB) return null;

  223.         int iNumACol = aadblA[0].length;
  224.         int iNumProductRow = aadblA.length;
  225.         int iNumProductCol = aadblB[0].length;
  226.         double[][] aadblProduct = new double[iNumProductRow][iNumProductCol];

  227.         if (0 == iNumACol || iNumACol != aadblB.length || 0 == iNumProductRow || 0 == iNumProductCol)
  228.             return null;

  229.         for (int iRow = 0; iRow < iNumProductRow; ++iRow) {
  230.             for (int iCol = 0; iCol < iNumProductCol; ++iCol) {
  231.                 aadblProduct[iRow][iCol] = 0.;

  232.                 for (int i = 0; i < iNumACol; ++i) {
  233.                     if (!org.drip.numerical.common.NumberUtil.IsValid (aadblA[iRow][i]) ||
  234.                         !org.drip.numerical.common.NumberUtil.IsValid (aadblB[i][iCol]))
  235.                         return null;

  236.                     aadblProduct[iRow][iCol] += aadblA[iRow][i] * aadblB[i][iCol];
  237.                 }
  238.             }
  239.         }

  240.         return aadblProduct;
  241.     }

  242.     /**
  243.      * Make a Square Diagonal Matrix from a Row
  244.      *
  245.      * @param adblA The Row Array
  246.      *
  247.      * @return The corresponding Square Diagonal Matrix
  248.      */

  249.     public static final double[][] MakeSquareDiagonal (
  250.         final double[] adblA)
  251.     {
  252.         if (null == adblA) return null;

  253.         int iNumElement = adblA.length;
  254.         double[][] aadblDiagonal = 0 == iNumElement ? null : new double[iNumElement][iNumElement];

  255.         if (0 == iNumElement) return null;

  256.         for (int i = 0; i < iNumElement; ++i) {
  257.             for (int j = 0; j < iNumElement; ++j)
  258.                 aadblDiagonal[i][j] = i == j ? adblA[i] : 0.;
  259.         }

  260.         return aadblDiagonal;
  261.     }

  262.     /**
  263.      * Invert a 2D Matrix using Cramer's Rule
  264.      *
  265.      * @param aadblA Input 2D Matrix
  266.      *
  267.      * @return The Inverted Matrix
  268.      */

  269.     public static final double[][] Invert2DMatrixUsingCramerRule (
  270.         final double[][] aadblA)
  271.     {
  272.         if (null == aadblA || 2 != aadblA.length || 2 != aadblA[0].length) return null;

  273.         for (int i = 0; i < 2; ++i) {
  274.             for (int j = 0; j < 2; ++j) {
  275.                 if (!org.drip.numerical.common.NumberUtil.IsValid (aadblA[i][j])) return null;
  276.             }
  277.         }

  278.         double dblScale = aadblA[0][0] * aadblA[1][1] - aadblA[0][1] * aadblA[1][0];

  279.         if (0. == dblScale) return null;

  280.         return new double[][] {{aadblA[1][1] / dblScale, -1. * aadblA[0][1] / dblScale}, {-1. * aadblA[1][0]
  281.             / dblScale, aadblA[0][0] / dblScale}};
  282.     }

  283.     /**
  284.      * Regularize the specified diagonal entry of the input matrix using Row Swapping
  285.      *
  286.      * @param mct The Input Matrix Complement Transform
  287.      *
  288.      * @return The Regularization was successful
  289.      */

  290.     public static final boolean RegularizeUsingRowSwap (
  291.         final org.drip.numerical.linearalgebra.MatrixComplementTransform mct)
  292.     {
  293.         if (null == mct) return false;

  294.         int iSize = mct.size();

  295.         double[][] aadblSource = mct.getSource();

  296.         double[][] aadblComplement = mct.getComplement();

  297.         for (int iDiagonal = 0; iDiagonal < iSize; ++iDiagonal) {
  298.             if (0. == aadblSource[iDiagonal][iDiagonal]) {
  299.                 int iSwapRow = iSize - 1;

  300.                 while (iSwapRow >= 0 && (0. == aadblSource[iSwapRow][iDiagonal] || 0. ==
  301.                     aadblSource[iDiagonal][iSwapRow]))
  302.                     --iSwapRow;

  303.                 if (0 > iSwapRow) {
  304.                     iSwapRow = 0;

  305.                     while (iSwapRow < iSize && 0. == aadblSource[iSwapRow][iDiagonal])
  306.                         ++iSwapRow;

  307.                     if (iSwapRow >= iSize) return false;
  308.                 }

  309.                 for (int iCol = 0; iCol < iSize; ++iCol) {
  310.                     double dblComplementDiagonalEntry = aadblComplement[iDiagonal][iCol];
  311.                     aadblComplement[iDiagonal][iCol] = aadblComplement[iSwapRow][iCol];
  312.                     aadblComplement[iSwapRow][iCol] = dblComplementDiagonalEntry;
  313.                     double dblSourceDiagonalEntry = aadblSource[iDiagonal][iCol];
  314.                     aadblSource[iDiagonal][iCol] = aadblSource[iSwapRow][iCol];
  315.                     aadblSource[iSwapRow][iCol] = dblSourceDiagonalEntry;
  316.                 }
  317.             }
  318.         }

  319.         /* for (int iDiagonal = 0; iDiagonal < iSize; ++iDiagonal) {
  320.             if (0. == aadblSource[iDiagonal][iDiagonal]) {
  321.                 org.drip.quant.common.NumberUtil.Print2DArray ("ZERO DIAG!", aadblSource, false);

  322.                 return false;
  323.             }
  324.         } */

  325.         return true;
  326.     }

  327.     /**
  328.      * Regularize the specified diagonal entry of the input matrix using Row Addition
  329.      *
  330.      * @param mct The Input Matrix Complement Transform
  331.      *
  332.      * @return The Regularization was successful
  333.      */

  334.     public static final boolean RegularizeUsingRowAddition (
  335.         final org.drip.numerical.linearalgebra.MatrixComplementTransform mct)
  336.     {
  337.         if (null == mct) return false;

  338.         int iSize = mct.size();

  339.         double[][] aadblSource = mct.getSource();

  340.         double[][] aadblComplement = mct.getComplement();

  341.         for (int iDiagonal = 0; iDiagonal < iSize; ++iDiagonal) {
  342.             if (0. == aadblSource[iDiagonal][iDiagonal]) {
  343.                 int iPivotRow = iSize - 1;

  344.                 while (0. == aadblSource[iPivotRow][iDiagonal] && iPivotRow >= 0) --iPivotRow;

  345.                 if (0 > iPivotRow) return false;

  346.                 for (int iCol = 0; iCol < iSize; ++iCol) {
  347.                     aadblSource[iDiagonal][iCol] += aadblSource[iPivotRow][iCol];
  348.                     aadblComplement[iDiagonal][iCol] += aadblComplement[iPivotRow][iCol];
  349.                 }
  350.             }
  351.         }

  352.         return true;
  353.     }

  354.     /**
  355.      * Pivot the Diagonal of the Input Matrix
  356.      *
  357.      * @param aadblA The Input Matrix
  358.      *
  359.      * @return The Matrix Complement Transform Instance
  360.      */

  361.     public static final org.drip.numerical.linearalgebra.MatrixComplementTransform PivotDiagonal (
  362.         final double[][] aadblA)
  363.     {
  364.         if (null == aadblA) return null;

  365.         int iSize = aadblA.length;
  366.         double[][] aadblSource = new double[iSize][iSize];
  367.         double[][] aadblComplement = new double[iSize][iSize];
  368.         org.drip.numerical.linearalgebra.MatrixComplementTransform mctOut = null;

  369.         if (0 == iSize || null == aadblA[0] || iSize != aadblA[0].length) return null;

  370.         for (int i = 0; i < iSize; ++i) {
  371.             for (int j = 0; j < iSize; ++j) {
  372.                 aadblSource[i][j] = aadblA[i][j];
  373.                 aadblComplement[i][j] = i == j ? 1. : 0.;
  374.             }
  375.         }

  376.         try {
  377.             mctOut = new org.drip.numerical.linearalgebra.MatrixComplementTransform (aadblSource,
  378.                 aadblComplement);
  379.         } catch (java.lang.Exception e) {
  380.             e.printStackTrace();

  381.             return null;
  382.         }

  383.         return RegularizeUsingRowSwap (mctOut) ? mctOut : null;
  384.     }

  385.     /**
  386.      * Invert the Source Matrix using Gaussian Elimination
  387.      *
  388.      * @param aadblSource Source Matrix
  389.      *
  390.      * @return The Inverted Matrix
  391.      */

  392.     public static final double[][] InvertUsingGaussianElimination (
  393.         final double[][] aadblSource)
  394.     {
  395.         org.drip.numerical.linearalgebra.MatrixComplementTransform mctRegularized =
  396.             org.drip.numerical.linearalgebra.Matrix.PivotDiagonal (aadblSource);

  397.         if (null == mctRegularized) return null;

  398.         double[][] aadblRegularizedSource = mctRegularized.getSource();

  399.         double[][] aadblRegularizedInverse = mctRegularized.getComplement();

  400.         int iSize = aadblRegularizedSource.length;

  401.         for (int iDiagonal = 0; iDiagonal < iSize; ++iDiagonal) {
  402.             if (0. == aadblRegularizedSource[iDiagonal][iDiagonal]) return null;

  403.             for (int iRow = 0; iRow < iSize; ++iRow) {
  404.                 if (iRow == iDiagonal || 0. == aadblRegularizedSource[iRow][iDiagonal]) continue;

  405.                 double dblColEntryEliminatorRatio = aadblRegularizedSource[iDiagonal][iDiagonal] /
  406.                     aadblRegularizedSource[iRow][iDiagonal];

  407.                 for (int iCol = 0; iCol < iSize; ++iCol) {
  408.                     aadblRegularizedSource[iRow][iCol] = aadblRegularizedSource[iRow][iCol] *
  409.                         dblColEntryEliminatorRatio - aadblRegularizedSource[iDiagonal][iCol];
  410.                     aadblRegularizedInverse[iRow][iCol] = aadblRegularizedInverse[iRow][iCol] *
  411.                         dblColEntryEliminatorRatio - aadblRegularizedInverse[iDiagonal][iCol];
  412.                 }
  413.             }
  414.         }

  415.         for (int iDiagonal = 0; iDiagonal < iSize; ++iDiagonal) {
  416.             double dblDiagScaleDown = aadblRegularizedSource[iDiagonal][iDiagonal];

  417.             if (0. == dblDiagScaleDown) return null;

  418.             for (int iCol = 0; iCol < iSize; ++iCol) {
  419.                 aadblRegularizedSource[iDiagonal][iCol] /= dblDiagScaleDown;
  420.                 aadblRegularizedInverse[iDiagonal][iCol] /= dblDiagScaleDown;
  421.             }
  422.         }

  423.         return aadblRegularizedInverse;
  424.     }

  425.     /**
  426.      * Invert the input matrix using the specified Method
  427.      *
  428.      * @param aadblA Input Matrix
  429.      * @param strMethod The Inversion Method
  430.      *
  431.      * @return The Inverted Matrix
  432.      */

  433.     public static final double[][] Invert (
  434.         final double[][] aadblA,
  435.         final java.lang.String strMethod)
  436.     {
  437.         if (null == aadblA) return null;

  438.         int iSize = aadblA.length;
  439.         double[][] aadblAInv = null;
  440.         double[][] aadblASource = new double[iSize][iSize];
  441.         double[][] aadblZ2YJack = new double[iSize][iSize];

  442.         if (0 == iSize || iSize != aadblA[0].length) return null;

  443.         for (int i = 0; i < iSize; ++i) {
  444.             for (int j = 0; j < iSize; ++j) {
  445.                 if (!org.drip.numerical.common.NumberUtil.IsValid (aadblASource[i][j] = aadblA[i][j]))
  446.                     return null;

  447.                 aadblZ2YJack[i][j] = i == j ? 1. : 0.;
  448.             }
  449.         }

  450.         for (int i = 0; i < iSize; ++i) {
  451.             if (0. == aadblASource[i][i] && !DiagonalizeRow (i, aadblASource, aadblZ2YJack)) return null;
  452.         }

  453.         if (null == strMethod || strMethod.isEmpty() || strMethod.equalsIgnoreCase ("GaussianElimination"))
  454.             aadblAInv = InvertUsingGaussianElimination (aadblASource);

  455.         if (null == aadblAInv || iSize != aadblAInv.length || iSize != aadblAInv[0].length) return null;

  456.         return Product (aadblAInv, aadblZ2YJack);
  457.     }

  458.     /**
  459.      * Compute the Rank of the Matrix
  460.      *
  461.      * @param aadblSource Source Matrix
  462.      *
  463.      * @return The Rank of the Matrix
  464.      *
  465.      * @throws java.lang.Exception Thrown if the Rank Cannot be computed
  466.      */

  467.     public static final int Rank (
  468.         final double[][] aadblSource)
  469.         throws java.lang.Exception
  470.     {
  471.         if (null == aadblSource) return 0;

  472.         int iNumRow = aadblSource.length;

  473.         if (iNumRow == 0) return 0;

  474.         int iNumCol = aadblSource[0].length;

  475.         for (int iScanRow = 0; iScanRow < iNumRow; ++iScanRow) {
  476.             if (!org.drip.numerical.common.NumberUtil.IsValid (aadblSource[iScanRow]))
  477.                 throw new java.lang.Exception ("Matrix::Rank => Invalid Inputs");
  478.         }

  479.         double[][] aadblRegularizedSource = iNumRow < iNumCol ?
  480.             org.drip.numerical.linearalgebra.Matrix.Transpose (aadblSource) : aadblSource;

  481.         int iNumDependentRow = 0;
  482.         int iProcessedRow = aadblRegularizedSource.length;
  483.         int iProcessedCol = aadblRegularizedSource[0].length;

  484.         if (1 == iNumRow || 1 == iNumCol) return iProcessedRow;

  485.         for (int iScanRow = 0; iScanRow < iProcessedCol; ++iScanRow) {
  486.             for (int iRow = 0; iRow < iProcessedCol; ++iRow) {
  487.                 if (iRow == iScanRow || 0. == aadblRegularizedSource[iRow][iScanRow]) continue;

  488.                 double dblColEntryEliminatorRatio = aadblRegularizedSource[iScanRow][iScanRow] /
  489.                     aadblRegularizedSource[iRow][iScanRow];

  490.                 for (int iCol = 0; iCol < iProcessedCol; ++iCol)
  491.                     aadblRegularizedSource[iRow][iCol] = aadblRegularizedSource[iRow][iCol] *
  492.                         dblColEntryEliminatorRatio - aadblRegularizedSource[iScanRow][iCol];
  493.             }
  494.         }

  495.         for (int iScanRow = 0; iScanRow < iProcessedCol; ++iScanRow) {
  496.             if (0. == org.drip.numerical.linearalgebra.Matrix.Modulus (aadblRegularizedSource[iScanRow]))
  497.                 ++iNumDependentRow;
  498.         }

  499.         return iProcessedRow - iNumDependentRow;
  500.     }

  501.     /**
  502.      * Transpose the specified Square Matrix
  503.      *
  504.      * @param aadblA The Input Square Matrix
  505.      *
  506.      * @return The Transpose of the Square Matrix
  507.      */

  508.     public static final double[][] Transpose (
  509.         final double[][] aadblA)
  510.     {
  511.         if (null == aadblA) return null;

  512.         int iRowSize = aadblA.length;

  513.         if (0 == iRowSize || null == aadblA[0]) return null;

  514.         int iColSize = aadblA[0].length;
  515.         double[][] aadblATranspose = new double[iColSize][iRowSize];

  516.         if (0 == iColSize) return null;

  517.         for (int i = 0; i < iColSize; ++i) {
  518.             for (int j = 0; j < iRowSize; ++j)
  519.                 aadblATranspose[i][j] = aadblA[j][i];
  520.         }

  521.         return aadblATranspose;
  522.     }

  523.     /**
  524.      * Compute the Cholesky-Banachiewicz Factorization of the specified Matrix.
  525.      *
  526.      * @param aadblA The Input Matrix
  527.      *
  528.      * @return The Factorized Matrix
  529.      */

  530.     public static final double[][] CholeskyBanachiewiczFactorization (
  531.         final double[][] aadblA)
  532.     {
  533.         if (null == aadblA) return null;

  534.         int iSize = aadblA.length;
  535.         double[][] aadblL = new double[iSize][iSize];

  536.         if (0 == iSize || null == aadblA[0] || iSize != aadblA[0].length) return null;

  537.         for (int i = 0; i < iSize; ++i) {
  538.             for (int j = 0; j < iSize; ++j) {
  539.                 aadblL[i][j] = 0.;

  540.                 if (i == j) {
  541.                     for (int k = 0; k < j; ++k)
  542.                         aadblL[j][j] -= aadblL[j][k] * aadblL[j][k];

  543.                     aadblL[j][j] = java.lang.Math.sqrt (aadblL[j][j] + aadblA[j][j]);
  544.                 } else if (i > j) {
  545.                     for (int k = 0; k < j; ++k)
  546.                         aadblL[i][j] -= aadblL[i][k] * aadblL[j][k];

  547.                     aadblL[i][j] = (aadblA[i][j] + aadblL[i][j]) / aadblL[j][j];
  548.                 }
  549.             }
  550.         }

  551.         return aadblL;
  552.     }

  553.     /**
  554.      * Dot Product of Vectors A and E
  555.      *
  556.      * @param adblA Vector A
  557.      * @param adblE Vector E
  558.      *
  559.      * @return The Dot Product
  560.      *
  561.      * @throws java.lang.Exception Thrown if the Dot-Product cannot be computed
  562.      */

  563.     public static final double DotProduct (
  564.         final double[] adblA,
  565.         final double[] adblE)
  566.         throws java.lang.Exception
  567.     {
  568.         if (null == adblA || null == adblE)
  569.             throw new java.lang.Exception ("Matrix::DotProduct => Invalid Inputs!");

  570.         int iSize = adblA.length;
  571.         double dblDotProduct = 0.;

  572.         if (0 == iSize || iSize != adblE.length)
  573.             throw new java.lang.Exception ("Matrix::DotProduct => Invalid Inputs!");

  574.         for (int i = 0; i < iSize; ++i)
  575.             dblDotProduct += adblE[i] * adblA[i];

  576.         return dblDotProduct;
  577.     }

  578.     /**
  579.      * Compute the Cross Product between the Specified Vectors
  580.      *
  581.      * @param vector1 Vector #1
  582.      * @param vector2 Vector #2
  583.      *
  584.      * @return The Cross Product
  585.      */

  586.     public static final double[][] CrossProduct (
  587.         final double[] vector1,
  588.         final double[] vector2)
  589.     {
  590.         if (null == vector1 || null == vector2)
  591.         {
  592.             return null;
  593.         }

  594.         int size1 = vector1.length;
  595.         int size2 = vector2.length;
  596.         double[][] crossProduct = 0 == size1 || 0 == size2 ? null : new double[size1][size2];

  597.         if (null == crossProduct)
  598.         {
  599.             return null;
  600.         }

  601.         for (int index1 = 0; index1 < size1; ++index1)
  602.         {
  603.             for (int index2 = 0; index2 < size2; ++index2)
  604.             {
  605.                 crossProduct[index1][index2] = vector1[index1] * vector2[index2];
  606.             }
  607.         }

  608.         return crossProduct;
  609.     }

  610.     /**
  611.      * Project the Vector A along the Vector E
  612.      *
  613.      * @param adblA Vector A
  614.      * @param adblE Vector E
  615.      *
  616.      * @return The Vector of Projection of A along E
  617.      */

  618.     public static final double[] Project (
  619.         final double[] adblA,
  620.         final double[] adblE)
  621.     {
  622.         if (null == adblA || null == adblE) return null;

  623.         int iSize = adblA.length;
  624.         double dblProjection = java.lang.Double.NaN;
  625.         double[] adblProjectAOnE = new double[iSize];

  626.         if (0 == iSize || iSize != adblE.length) return null;

  627.         try {
  628.             dblProjection = DotProduct (adblA, adblE) / DotProduct (adblE, adblE);
  629.         } catch (java.lang.Exception e) {
  630.             e.printStackTrace();

  631.             return null;
  632.         }

  633.         for (int i = 0; i < iSize; ++i)
  634.             adblProjectAOnE[i] = adblE[i] * dblProjection;

  635.         return adblProjectAOnE;
  636.     }

  637.     /**
  638.      * Compute the Sum of the Input Vector
  639.      *
  640.      * @param adbl The Input Vector
  641.      *
  642.      * @return TRUE - The Sum of the Input Vector
  643.      *
  644.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  645.      */

  646.     public static final double Sum (
  647.         final double[] adbl)
  648.         throws java.lang.Exception
  649.     {
  650.         if (null == adbl || !org.drip.numerical.common.NumberUtil.IsValid (adbl))
  651.             throw new java.lang.Exception ("Matrix::Sum => Invalid Inputs");

  652.         double dblSum = 0.;
  653.         int iSize = adbl.length;

  654.         if (0 == iSize) throw new java.lang.Exception ("Matrix::Sum => Invalid Inputs");

  655.         for (int i = 0; i < iSize; ++i)
  656.             dblSum += adbl[i];

  657.         return dblSum;
  658.     }

  659.     /**
  660.      * Compute the Modulus of the Input Vector
  661.      *
  662.      * @param adbl The Input Vector
  663.      *
  664.      * @return TRUE - The Modulus of the Input Vector
  665.      *
  666.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  667.      */

  668.     public static final double Modulus (
  669.         final double[] adbl)
  670.         throws java.lang.Exception
  671.     {
  672.         if (null == adbl || !org.drip.numerical.common.NumberUtil.IsValid (adbl))
  673.             throw new java.lang.Exception ("Matrix::Modulus => Invalid Inputs");

  674.         double dblModulus = 0.;
  675.         int iSize = adbl.length;

  676.         if (0 == iSize) throw new java.lang.Exception ("Matrix::Modulus => Invalid Inputs");

  677.         for (int i = 0; i < iSize; ++i)
  678.             dblModulus += adbl[i] * adbl[i];

  679.         return java.lang.Math.sqrt (dblModulus);
  680.     }

  681.     /**
  682.      * Indicate if the Array Entries are Positive or Zero
  683.      *
  684.      * @param adbl The Array
  685.      *
  686.      * @return TRUE - The Array Entries are Positive or Zero
  687.      *
  688.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  689.      */

  690.     public static final boolean PositiveOrZero (
  691.         final double[] adbl)
  692.         throws java.lang.Exception
  693.     {
  694.         if (null == adbl || !org.drip.numerical.common.NumberUtil.IsValid (adbl))
  695.             throw new java.lang.Exception ("Matrix::PositiveOrZero => Invalid Inputs");

  696.         int iSize = adbl.length;

  697.         if (0 == iSize) throw new java.lang.Exception ("Matrix::PositiveOrZero => Invalid Inputs");

  698.         for (int i = 0; i < iSize; ++i) {
  699.             if (0. > adbl[i]) return false;
  700.         }

  701.         return true;
  702.     }

  703.     /**
  704.      * Indicate if the Array Entries are Negative or Zero
  705.      *
  706.      * @param adbl The Array
  707.      *
  708.      * @return The Array Entries are Negative or Zero
  709.      *
  710.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  711.      */

  712.     public static final boolean NegativeOrZero (
  713.         final double[] adbl)
  714.         throws java.lang.Exception
  715.     {
  716.         if (null == adbl || !org.drip.numerical.common.NumberUtil.IsValid (adbl))
  717.             throw new java.lang.Exception ("Matrix::NegativeOrZero => Invalid Inputs");

  718.         int iSize = adbl.length;

  719.         if (0 == iSize)  throw new java.lang.Exception ("Matrix::NegativeOrZero => Invalid Inputs");

  720.         for (int i = 0; i < iSize; ++i) {
  721.             if (0. < adbl[i]) return false;
  722.         }

  723.         return true;
  724.     }

  725.     /**
  726.      * Indicate if the Array Entries are Positive Linearly Independent
  727.      *
  728.      * @param adbl The Array
  729.      *
  730.      * @return TRUE - The Array Entries are Positive Linearly Independent
  731.      *
  732.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  733.      */

  734.     public static final boolean PositiveLinearlyIndependent (
  735.         final double[] adbl)
  736.         throws java.lang.Exception
  737.     {
  738.         return !PositiveOrZero (adbl) && !NegativeOrZero (adbl);
  739.     }

  740.     /**
  741.      * Normalize the Input Vector
  742.      *
  743.      * @param adbl The Input Vector
  744.      *
  745.      * @return The Normalized Vector
  746.      */

  747.     public static final double[] Normalize (
  748.         final double[] adbl)
  749.     {
  750.         if (null == adbl) return null;

  751.         double dblNorm = 0.;
  752.         int iSize = adbl.length;
  753.         double[] adblNormalized = new double[iSize];

  754.         if (0 == iSize) return null;

  755.         for (int i = 0; i < iSize; ++i)
  756.             dblNorm += adbl[i] * adbl[i];

  757.         dblNorm = java.lang.Math.sqrt (dblNorm);

  758.         for (int i = 0; i < iSize; ++i)
  759.             adblNormalized[i] = adbl[i] / dblNorm;

  760.         return adblNormalized;
  761.     }

  762.     /**
  763.      * Orthogonalize the Specified Matrix Using the Graham-Schmidt Method
  764.      *
  765.      * @param aadblV The Input Matrix
  766.      *
  767.      * @return The Orthogonalized Matrix
  768.      */

  769.     public static final double[][] GrahamSchmidtOrthogonalization (
  770.         final double[][] aadblV)
  771.     {
  772.         if (null == aadblV) return null;

  773.         int iSize = aadblV.length;
  774.         double[][] aadblU = new double[iSize][iSize];

  775.         if (0 == iSize || null == aadblV[0] || iSize != aadblV[0].length) return null;

  776.         for (int i = 0; i < iSize; ++i) {
  777.             for (int j = 0; j < iSize; ++j)
  778.                 aadblU[i][j] = aadblV[i][j];

  779.             for (int j = 0; j < i; ++j) {
  780.                 double dblProjectionAmplitude = java.lang.Double.NaN;

  781.                 try {
  782.                     dblProjectionAmplitude = DotProduct (aadblV[i], aadblU[j]) / DotProduct (aadblU[j],
  783.                         aadblU[j]);
  784.                 } catch (java.lang.Exception e) {
  785.                     e.printStackTrace();

  786.                     return null;
  787.                 }

  788.                 for (int k = 0; k < iSize; ++k)
  789.                     aadblU[i][k] -= dblProjectionAmplitude * aadblU[j][k];
  790.             }
  791.         }

  792.         return aadblU;
  793.     }

  794.     /**
  795.      * Orthonormalize the Specified Matrix Using the Graham-Schmidt Method
  796.      *
  797.      * @param aadblV The Input Matrix
  798.      *
  799.      * @return The Orthonormalized Matrix
  800.      */

  801.     public static final double[][] GrahamSchmidtOrthonormalization (
  802.         final double[][] aadblV)
  803.     {
  804.         double[][] aadblVOrthogonal = GrahamSchmidtOrthogonalization (aadblV);

  805.         if (null == aadblVOrthogonal) return null;

  806.         int iSize = aadblVOrthogonal.length;

  807.         double[][] aadblVOrthonormal = new double[iSize][];

  808.         for (int i = 0; i < iSize; ++i)
  809.             aadblVOrthonormal[i] = Normalize (aadblVOrthogonal[i]);

  810.         return aadblVOrthonormal;
  811.     }

  812.     /**
  813.      * Perform a QR Decomposition on the Input Matrix
  814.      *
  815.      * @param aadblA The Input Matrix
  816.      *
  817.      * @return The Output of QR Decomposition
  818.      */

  819.     public static final org.drip.numerical.linearalgebra.QR QRDecomposition (
  820.         final double[][] aadblA)
  821.     {
  822.         double[][] aadblQ = GrahamSchmidtOrthonormalization (aadblA);

  823.         if (null == aadblQ) return null;

  824.         int iSize = aadblQ.length;
  825.         double[][] aadblR = new double[iSize][iSize];

  826.         try {
  827.             for (int i = 0; i < iSize; ++i) {
  828.                 for (int j = 0; j < iSize; ++j)
  829.                     aadblR[i][j] = i > j ? DotProduct (aadblQ[i], aadblA[j]) : 0.;
  830.             }

  831.             return new org.drip.numerical.linearalgebra.QR (aadblQ, aadblR);
  832.         } catch (java.lang.Exception e) {
  833.             e.printStackTrace();
  834.         }

  835.         return null;
  836.     }

  837.     /**
  838.      * Retrieve the Triangular Type of the Matrix
  839.      *
  840.      * @param aadblA The Input Matrix
  841.      * @param dblFloor The Floor Level that means "Zero"
  842.      *
  843.      * @return The Triangular Type
  844.      */

  845.     public static final int TriangularType (
  846.         final double[][] aadblA,
  847.         final double dblFloor)
  848.     {
  849.         if (null == aadblA || !org.drip.numerical.common.NumberUtil.IsValid (dblFloor) || dblFloor < 0.)
  850.             return NON_TRIANGULAR;

  851.         int iSize = aadblA.length;
  852.         boolean bLowerTriangular = true;
  853.         boolean bUpperTriangular = true;

  854.         if (1 >= iSize || null == aadblA[0] || iSize != aadblA[0].length) return NON_TRIANGULAR;

  855.         for (int i = 0; i < iSize; ++i) {
  856.             for (int j = 0; j < iSize; ++j) {
  857.                 if (i > j) {
  858.                     if (java.lang.Math.abs (aadblA[i][j]) > dblFloor) bLowerTriangular = false;
  859.                 } else if (i < j) {
  860.                     if (java.lang.Math.abs (aadblA[i][j]) > dblFloor) bUpperTriangular = false;
  861.                 }
  862.             }
  863.         }

  864.         if (bLowerTriangular && bUpperTriangular) return LOWER_AND_UPPER_TRIANGULAR;

  865.         if (bLowerTriangular && !bUpperTriangular) return LOWER_TRIANGULAR;

  866.         if (!bLowerTriangular && bUpperTriangular) return UPPER_TRIANGULAR;

  867.         return NON_TRIANGULAR;
  868.     }

  869.     /**
  870.      * Compute the Rayleigh Quotient given the Matrix and one of its Eigenvector
  871.      *
  872.      * @param matrix The Given Matrix
  873.      * @param eigenvector The corresponding Eigenvector
  874.      *
  875.      * @return The Computed Rayleigh Quotient
  876.      *
  877.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  878.      */

  879.     public static final double RayleighQuotient (
  880.         final double[][] matrix,
  881.         final double[] eigenvector)
  882.         throws java.lang.Exception
  883.     {
  884.         return org.drip.numerical.linearalgebra.Matrix.DotProduct (
  885.             eigenvector,
  886.             org.drip.numerical.linearalgebra.Matrix.Product (
  887.                 matrix,
  888.                 eigenvector
  889.             )
  890.         );
  891.     }

  892.     /**
  893.      * Scale the Entries of the Input Vector by the Factor
  894.      *
  895.      * @param vector The Input Vector
  896.      * @param scaleFactor The Scale Factor
  897.      *
  898.      * @return The Scaled Matrix
  899.      */

  900.     public static final double[] Scale1D (
  901.         final double[] vector,
  902.         final double scaleFactor)
  903.     {
  904.         if (null == vector || !org.drip.numerical.common.NumberUtil.IsValid (scaleFactor))
  905.         {
  906.             return null;
  907.         }

  908.         int rowCount = vector.length;
  909.         double[] scaledVector = 0 == rowCount ? null : new double[rowCount];

  910.         for (int rowIndex = 0; rowIndex < rowCount ; ++rowIndex)
  911.         {
  912.             scaledVector[rowIndex] = vector[rowIndex] * scaleFactor;
  913.         }

  914.         return scaledVector;
  915.     }

  916.     /**
  917.      * Scale the Entries of the Input Matrix by the Factor
  918.      *
  919.      * @param matrix The Input Matrix
  920.      * @param scaleFactor The Scale Factor
  921.      *
  922.      * @return The Scaled Matrix
  923.      */

  924.     public static final double[][] Scale2D (
  925.         final double[][] matrix,
  926.         final double scaleFactor)
  927.     {
  928.         if (null == matrix || !org.drip.numerical.common.NumberUtil.IsValid (scaleFactor))
  929.         {
  930.             return null;
  931.         }

  932.         int rowCount = matrix.length;
  933.         int columnCount = 0 == rowCount || null == matrix[0] ? 0 : matrix[0].length;
  934.         double[][] scaledMatrix = 0 == columnCount ? null : new double[rowCount][columnCount];

  935.         for (int rowIndex = 0; rowIndex < rowCount ; ++rowIndex)
  936.         {
  937.             for (int columnIndex = 0; columnIndex < columnCount ; ++columnIndex)
  938.             {
  939.                 scaledMatrix[rowIndex][columnIndex] = matrix[rowIndex][columnIndex] * scaleFactor;
  940.             }
  941.         }

  942.         return scaledMatrix;
  943.     }

  944.     /**
  945.      * Indicate if the Specified Matrix is Diagonal
  946.      *
  947.      * @param matrix The Matrix
  948.      *
  949.      * @return TRUE - The Specified Matrix is Diagonal
  950.      */

  951.     public static final boolean IsDiagonal (
  952.         final double[][] matrix)
  953.     {
  954.        if (null == matrix)
  955.        {
  956.            return false;
  957.        }

  958.        int rowCount = matrix.length;
  959.        int columnCount = 0 == rowCount || null == matrix[0] ? 0 : matrix[0].length;

  960.        for (int rowIndex = 0;
  961.             rowIndex < rowCount;
  962.             ++rowIndex)
  963.        {
  964.            for (int columnIndex = 0;
  965.                 columnIndex < columnCount;
  966.                 ++columnIndex)
  967.            {
  968.                if (rowIndex != columnIndex && 0. != matrix[rowIndex][columnIndex])
  969.                {
  970.                    return false;
  971.                }
  972.            }
  973.        }

  974.        return true;
  975.     }
  976. }