daily pastebin goal
90%
SHARE
TWEET

immutable-math-matrix

a guest May 16th, 2018 87 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. export { Matrix };
  2.  
  3. import {
  4.   Vector
  5. } from './vector';
  6.  
  7. class Matrix {
  8.  
  9.   public static makeIdentityMatrix(
  10.     {
  11.       numberOfRows
  12.     , numberOfColumns
  13.     }: {
  14.       numberOfRows: number
  15.     , numberOfColumns: number
  16.     }
  17.   ): Matrix {
  18.     Matrix.checkSize(
  19.       {
  20.         numberOfRows: numberOfRows
  21.       , numberOfColumns: numberOfColumns
  22.       }
  23.     );
  24.  
  25.     let elements = [];
  26.  
  27.     for (
  28.       let ir = 0;
  29.       ir < numberOfRows;
  30.       ir++
  31.     ) {
  32.       elements[ ir ] = [];
  33.  
  34.       for (
  35.         let ic = 0;
  36.         ic < numberOfColumns;
  37.         ic++
  38.       ) {
  39.         if (
  40.           ir === ic
  41.         ) {
  42.           elements[ ir ][ ic ] = 1;
  43.         }
  44.         else {
  45.           elements[ ir ][ ic ] = 0;
  46.         }
  47.       } // column loop
  48.     } // row loop
  49.  
  50.     let matrix = new Matrix(
  51.       elements
  52.     );
  53.  
  54.     return matrix;
  55.   }
  56.   public static makeEmptyMatrix(
  57.     {
  58.       numberOfRows
  59.     , numberOfColumns
  60.     }: {
  61.       numberOfRows: number
  62.     , numberOfColumns: number
  63.     }
  64.   ): Matrix {
  65.     Matrix.checkSize(
  66.       {
  67.         numberOfRows: numberOfRows
  68.       , numberOfColumns: numberOfColumns
  69.       }
  70.     );
  71.  
  72.     let elements = [];
  73.  
  74.     for (
  75.       let ir = 0;
  76.       ir < numberOfRows;
  77.       ir++
  78.     ) {
  79.       elements[ ir ] = [];
  80.      
  81.       for (
  82.         let ic = 0;
  83.         ic < numberOfColumns;
  84.         ic++
  85.       ) {
  86.         elements[ ir ][ ic ] = 0;
  87.       } // column loop
  88.     } // row loop
  89.  
  90.     let matrix = new Matrix(
  91.       elements
  92.     );
  93.  
  94.     return matrix;
  95.   }
  96.  
  97.   public static addMatrices(
  98.     {
  99.       matrixA
  100.     , matrixB
  101.     }: {
  102.       matrixA: Matrix
  103.     , matrixB: Matrix
  104.     }
  105.   ): Matrix {
  106.     Matrix.checkDimensionsSame(
  107.       {
  108.         matrixA: matrixA
  109.       , matrixB: matrixB
  110.       }
  111.     );
  112.  
  113.     let rows = matrixA.getNumberOfRows();
  114.     let columns = matrixA.getNumberOfColumns();
  115.  
  116.     let aElements = matrixA.getElements();
  117.     let bElements = matrixB.getElements();
  118.  
  119.     let cElements = [];
  120.  
  121.     for (
  122.       let ir = 0;
  123.       ir < rows;
  124.       ir++
  125.     ) {
  126.       cElements[ ir ] = [];
  127.  
  128.       for (
  129.         let ic = 0;
  130.         ic < columns;
  131.         ic++
  132.       ) {
  133.         cElements[ ir ][ ic ] = (
  134.           aElements[ ir ][ ic ]
  135.           + bElements[ ir ][ ic ]
  136.         );
  137.       } // column loop
  138.     } // row loop
  139.  
  140.     let matrixC = new Matrix(
  141.       cElements
  142.     );
  143.  
  144.     return matrixC;
  145.   }
  146.   public static subtractMatrices(
  147.     {
  148.       matrixA
  149.     , matrixB
  150.     }: {
  151.       matrixA: Matrix
  152.     , matrixB: Matrix
  153.     }
  154.   ): Matrix {
  155.     Matrix.checkDimensionsSame(
  156.       {
  157.         matrixA: matrixA
  158.       , matrixB: matrixB
  159.       }
  160.     );
  161.  
  162.     let rows = matrixA.getNumberOfRows();
  163.     let columns = matrixA.getNumberOfColumns();
  164.  
  165.     let aElements = matrixA.getElements();
  166.     let bElements = matrixB.getElements();
  167.  
  168.     let cElements = [];
  169.  
  170.     for (
  171.       let ir = 0;
  172.       ir < rows;
  173.       ir++
  174.     ) {
  175.       cElements[ ir ] = [];
  176.  
  177.       for (
  178.         let ic = 0;
  179.         ic < columns;
  180.         ic++
  181.       ) {
  182.         cElements[ ir ][ ic ] = (
  183.           aElements[ ir ][ ic ]
  184.           - bElements[ ir ][ ic ]
  185.         );
  186.       } // column loop
  187.     } // row loop
  188.  
  189.     let matrixC = new Matrix(
  190.       cElements
  191.     );
  192.  
  193.     return matrixC;
  194.   }
  195.   public static multiplyMatrices(
  196.     {
  197.       matrixA
  198.     , matrixB
  199.     }: {
  200.       matrixA: Matrix
  201.     , matrixB: Matrix
  202.     }
  203.   ): Matrix {
  204.     Matrix.checkDimensionsMatchUp(
  205.       {
  206.         matrixA: matrixA
  207.       , matrixB: matrixB
  208.       }
  209.     );
  210.  
  211.     let aRows = matrixA.getNumberOfRows();
  212.     let aColumns = matrixA.getNumberOfColumns();
  213.     let bColumns = matrixB.getNumberOfColumns();
  214.     let aElements = matrixA.getElements();
  215.     let bElements = matrixB.getElements();
  216.  
  217.     let cElements = [];
  218.  
  219.     for (
  220.       let icr = 0;
  221.       icr < aRows;
  222.       icr++
  223.     ) {
  224.       cElements[ icr ] = [];
  225.  
  226.       for (
  227.         let icc = 0;
  228.         icc < bColumns;
  229.         icc++
  230.       ) {
  231.  
  232.         let cElementSum = 0;
  233.  
  234.         for (
  235.           let iac = 0;
  236.           iac < aColumns;
  237.           iac++
  238.         ) {
  239.           cElementSum = (
  240.             cElementSum
  241.             + (
  242.               aElements[ icr ][ iac ]
  243.               * bElements[ iac ][ icc ]
  244.             )
  245.           );
  246.         } // a column loop
  247.  
  248.         cElements[ icr ][ icc ] = cElementSum;
  249.       } // c column loop
  250.     } // c row loop
  251.  
  252.     let matrixC = new Matrix(
  253.       cElements
  254.     );
  255.  
  256.     return matrixC;
  257.   }
  258.  
  259.   public static lerpBetweenMatrices(
  260.     {
  261.       matrixA
  262.     , matrixB
  263.     , progress // ranges from 0.0 to 1.0
  264.     }: {
  265.       matrixA: Matrix
  266.     , matrixB: Matrix
  267.     , progress: number
  268.     }
  269.   ): Matrix {
  270.     Matrix.checkLerpProgress(
  271.       progress
  272.     );
  273.     Matrix.checkDimensionsSame(
  274.       {
  275.         matrixA: matrixA
  276.       , matrixB: matrixB
  277.       }
  278.     );
  279.  
  280.     let delta = matrixB.subtractMatrix(
  281.       matrixA
  282.     );
  283.     delta = delta.multiplyMatrixByScalar(
  284.       progress
  285.     );
  286.  
  287.     let result = matrixA.addMatrix(
  288.       delta
  289.     );
  290.  
  291.     return result;
  292.   }
  293.  
  294.   private static checkSize(
  295.     {
  296.       numberOfRows
  297.     , numberOfColumns
  298.     }: {
  299.       numberOfRows: number
  300.     , numberOfColumns: number
  301.     }
  302.   ): void {
  303.     if (
  304.       numberOfColumns < 2
  305.       || numberOfRows < 2
  306.     ) {
  307.       throw Error(
  308.         'matrix dimensions below minimum of 2'
  309.       );
  310.     }
  311.   }
  312.   private static checkDimensionsMatchUp(
  313.     {
  314.       matrixA
  315.     , matrixB
  316.     }: {
  317.       matrixA: Matrix
  318.     , matrixB: Matrix
  319.     }
  320.   ): void {
  321.     let aColumns = matrixA.getNumberOfColumns();
  322.     let bRows = matrixB.getNumberOfRows();
  323.  
  324.     if (
  325.       aColumns !== bRows
  326.     ) {
  327.       throw Error(
  328.         'number of columns and rows do not match up right'
  329.       );
  330.     }
  331.   }
  332.   private static checkDimensionsSame(
  333.     {
  334.       matrixA
  335.     , matrixB
  336.     }: {
  337.       matrixA: Matrix
  338.     , matrixB: Matrix
  339.     }
  340.   ): void {
  341.     let aColumns = matrixA.getNumberOfColumns();
  342.     let aRows = matrixA.getNumberOfRows();
  343.     let bColumns = matrixB.getNumberOfColumns();
  344.     let bRows = matrixB.getNumberOfRows();
  345.  
  346.     if (
  347.       aColumns !== bColumns
  348.       || aRows !== bRows
  349.     ) {
  350.       throw Error(
  351.         'matrices have different dimensions'
  352.       );
  353.     }
  354.   }
  355.   private static checkLerpProgress(
  356.     progress
  357.   ): void {
  358.     if (
  359.       progress < 0
  360.       || progress > 1
  361.     ) {
  362.       throw Error(
  363.         'progress out of valid range'
  364.       );
  365.     }
  366.   }
  367.  
  368.   private readonly elements: number[][];
  369.   private readonly numberOfColumns: number;
  370.   private readonly numberOfRows: number;
  371.   private readonly square: boolean;
  372.   private determinant: number;
  373.   // to decide: cache results of transpose, inverse, cofactors, minor matrices?
  374.  
  375.   public constructor(
  376.     elements: number[][]
  377.   ) {
  378.     this.checkElements(
  379.       elements
  380.     );
  381.  
  382.     this.elements = elements;
  383.     // calculate number of rows and columns
  384.     this.numberOfRows = elements.length;
  385.     this.numberOfColumns = elements[ 0 ].length;
  386.     // calculate is square
  387.     this.square = (
  388.       this.numberOfColumns
  389.       === this.numberOfRows
  390.     );
  391.   }
  392.  
  393.   public getNumberOfColumns(): number {
  394.     return this.numberOfColumns;
  395.   }
  396.   public getNumberOfRows(): number {
  397.     return this.numberOfRows;
  398.   }
  399.  
  400.   public isSquare(): boolean {
  401.     return this.square;
  402.   }
  403.  
  404.   public getElements(): number[][] {
  405.     return this.elements;
  406.   }
  407.   public getElement(
  408.     {
  409.       rowIndex
  410.     , columnIndex
  411.     }: {
  412.       rowIndex: number
  413.     , columnIndex: number
  414.     }
  415.   ): number {
  416.     this.checkElementIndex(
  417.       {
  418.         columnIndex: columnIndex
  419.       , rowIndex: rowIndex
  420.       }
  421.     );
  422.  
  423.     return this.elements[ rowIndex ][ columnIndex ];
  424.   }
  425.  
  426.   public getColumnAsVector(
  427.     columnIndex: number
  428.   ) {
  429.     this.checkElementIndex(
  430.       {
  431.         rowIndex: 0
  432.       , columnIndex: columnIndex
  433.       }
  434.     );
  435.  
  436.     let components = [];
  437.    
  438.     for (
  439.       let ir = 0;
  440.       ir < this.numberOfRows;
  441.       ir++
  442.     ) {
  443.       components[ ir ] = this.elements[ ir ][ columnIndex ];
  444.     }
  445.  
  446.     let vector = new Vector(
  447.       components
  448.     );
  449.  
  450.     return vector;
  451.   }
  452.   public getRowAsVector(
  453.     rowIndex: number
  454.   ) {
  455.     this.checkElementIndex(
  456.       {
  457.         rowIndex: rowIndex
  458.       , columnIndex: 0
  459.       }
  460.     );
  461.  
  462.     let components = [];
  463.    
  464.     for (
  465.       let ic = 0;
  466.       ic < this.numberOfColumns;
  467.       ic++
  468.     ) {
  469.       components[ ic ] = this.elements[ rowIndex ][ ic ];
  470.     }
  471.  
  472.     let vector = new Vector(
  473.       components
  474.     );
  475.  
  476.     return vector;
  477.   }
  478.  
  479.   public getTranspose(): Matrix {
  480.     let elements = [];
  481.  
  482.     for (
  483.       let ir = 0;
  484.       ir < this.numberOfColumns;
  485.       ir++
  486.     ) {
  487.       elements[ ir ] = [];
  488.  
  489.       for (
  490.         let ic = 0;
  491.         ic < this.numberOfRows;
  492.         ic++
  493.       ) {
  494.         elements[ ir ][ ic ] = this.elements[ ic ][ ir ];
  495.       } // column loop
  496.     } // row loop
  497.  
  498.     let transpose = new Matrix(
  499.       elements
  500.     );
  501.  
  502.     return transpose;
  503.   }
  504.   public getInverse(): Matrix {
  505.     if (
  506.       !this.isSquare()
  507.     ) {
  508.       throw Error(
  509.         'matrix is not square'
  510.       );
  511.     }
  512.  
  513.     let determinant = this.getDeterminant();
  514.     if ( determinant === 0 ) {
  515.       console.log(
  516.         'determinant is zero, no inverse'
  517.       );
  518.       return null;
  519.     }
  520.  
  521.     let elements = [];
  522.  
  523.     for (
  524.       let ir = 0;
  525.       ir < this.numberOfRows;
  526.       ir++
  527.     ) {
  528.       elements[ ir ] = [];
  529.  
  530.       for (
  531.         let ic = 0;
  532.         ic < this.numberOfColumns;
  533.         ic++
  534.       ) {
  535.         elements[ ir ][ ic ] = this.getCofactorFor(
  536.           {
  537.             rowIndex: ir,
  538.             columnIndex: ic
  539.           }
  540.         );
  541.       } // column loop
  542.     } // row loop
  543.  
  544.     let cofactorMatrix = new Matrix(
  545.       elements
  546.     );
  547.     let inverse = cofactorMatrix.getTranspose();
  548.     inverse = inverse.divideMatrixByScalar(
  549.       determinant
  550.     );
  551.  
  552.     return inverse;
  553.   }
  554.   public getDeterminant(): number {
  555.     if (
  556.       this.determinant === undefined
  557.     ) {
  558.       this.calculateDeterminant();
  559.     }
  560.  
  561.     return this.determinant;
  562.   }
  563.   public getCofactorFor(
  564.     {
  565.       rowIndex
  566.     , columnIndex
  567.     }: {
  568.       rowIndex: number
  569.     , columnIndex: number
  570.     }
  571.   ): number {
  572.     this.checkElementIndex(
  573.       {
  574.         rowIndex: rowIndex
  575.       , columnIndex: columnIndex
  576.       }
  577.     );
  578.     if (
  579.       this.numberOfColumns === 2
  580.       || this.numberOfRows === 2
  581.     ) {
  582.       throw Error(
  583.         'get cofactor unsupported for matrix 2'
  584.       );
  585.     }
  586.  
  587.     let minor = this.getMinorMatrixFor(
  588.       {
  589.         rowIndex: rowIndex,
  590.         columnIndex: columnIndex
  591.       }
  592.     );
  593.  
  594.     let determinant = minor.getDeterminant();
  595.  
  596.     // todo: check whether sign uses indices starting at 0 or 1
  597.     let sign = Math.pow(
  598.       -1,
  599.       ( rowIndex + columnIndex )
  600.     );
  601.  
  602.     let cofactor = sign * determinant;
  603.  
  604.     return cofactor;
  605.   }
  606.   public getMinorMatrixFor(
  607.     {
  608.       rowIndex
  609.     , columnIndex
  610.     }: {
  611.       rowIndex: number
  612.     , columnIndex: number
  613.     }
  614.   ): Matrix {
  615.     this.checkElementIndex(
  616.       {
  617.         rowIndex: rowIndex
  618.       , columnIndex: columnIndex
  619.       }
  620.     );
  621.     if (
  622.       this.numberOfColumns === 2
  623.       || this.numberOfRows === 2
  624.     ) {
  625.       throw Error(
  626.         'get minor matrix unsupported for matrix 2'
  627.       );
  628.     }
  629.  
  630.     let elements = [];
  631.     let mRows = this.numberOfRows - 1;
  632.     let mColumns = this.numberOfColumns - 1;
  633.  
  634.     for (
  635.       let ir = 0;
  636.       ir < mRows;
  637.       ir++
  638.     ) {
  639.       elements[ ir ] = [];
  640.  
  641.       for (
  642.         let ic = 0;
  643.         ic < mColumns;
  644.         ic++
  645.       ) {
  646.         let r;
  647.         let c;
  648.  
  649.         if ( // todo: check whether > or >=
  650.           ir >= rowIndex
  651.         ) {
  652.           r = ir + 1;
  653.         }
  654.         else {
  655.           r = ir;
  656.         }
  657.  
  658.         if ( // todo: check whether > or >=
  659.           ic >= columnIndex
  660.         ) {
  661.           c = ic + 1;
  662.         }
  663.         else {
  664.           c = ic;
  665.         }
  666.  
  667.         elements[ ir ][ ic ] = this.elements[ r ][ c ];
  668.       } // column loop
  669.     } // row loop
  670.  
  671.     let minor = new Matrix(
  672.       elements
  673.     );
  674.  
  675.     return minor;
  676.   }
  677.  
  678.   public setElement(
  679.     {
  680.       rowIndex
  681.     , columnIndex
  682.     , value
  683.     }: {
  684.       rowIndex: number
  685.     , columnIndex: number
  686.     , value: number
  687.     }
  688.   ): Matrix {
  689.     this.checkElementIndex(
  690.       {
  691.         columnIndex: columnIndex
  692.       , rowIndex: rowIndex
  693.       }
  694.     );
  695.  
  696.     let elements = [];
  697.  
  698.     for (
  699.       let ir = 0;
  700.       ir < this.numberOfRows;
  701.       ir++
  702.     ) {
  703.       elements[ ir ] = [];
  704.  
  705.       for (
  706.         let ic = 0;
  707.         ic < this.numberOfColumns;
  708.         ic++
  709.       ) {
  710.         if (
  711.           ic === columnIndex
  712.           && ir === rowIndex
  713.         ) {
  714.           elements[ ir ][ ic ] = value;
  715.         }
  716.         else {
  717.           elements[ ir ][ ic ] = this.elements[ ir ][ ic ];
  718.         }
  719.       } // column loop
  720.     } // row loop
  721.  
  722.     let matrix = new Matrix(
  723.       elements
  724.     );
  725.  
  726.     return matrix;
  727.   }
  728.  
  729.   public setColumnFromVector(
  730.     {
  731.       columnIndex
  732.     , vector
  733.     }: {
  734.       columnIndex: number
  735.     , vector: Vector
  736.     }
  737.   ): Matrix {
  738.     this.checkElementIndex(
  739.       {
  740.         rowIndex: 0
  741.       , columnIndex: columnIndex
  742.       }
  743.     );
  744.     this.checkComponentsMatchColumns(
  745.       vector
  746.     );
  747.  
  748.     let elements = [];
  749.  
  750.     for (
  751.       let ir = 0;
  752.       ir < this.numberOfRows;
  753.       ir++
  754.     ) {
  755.       elements[ ir ] = [];
  756.  
  757.       for (
  758.         let ic = 0;
  759.         ic < this.numberOfColumns;
  760.         ic++
  761.       ) {
  762.         if (
  763.           ic === columnIndex
  764.         ) {
  765.           elements[ ir ][ ic ] = vector.getComponent( ir );
  766.         }
  767.         else {
  768.           elements[ ir ][ ic ] = this.elements[ ir ][ ic ];
  769.         }
  770.       } // column loop
  771.     } // row loop
  772.  
  773.     let matrix = new Matrix(
  774.       elements
  775.     );
  776.  
  777.     return matrix;
  778.   }
  779.   public setRowFromVector(
  780.     {
  781.       rowIndex
  782.     , vector
  783.     }: {
  784.       rowIndex: number
  785.     , vector: Vector
  786.     }
  787.   ): Matrix {
  788.     this.checkElementIndex(
  789.       {
  790.         rowIndex: rowIndex
  791.       , columnIndex: 0
  792.       }
  793.     );
  794.     this.checkComponentsMatchRows(
  795.       vector
  796.     );
  797.  
  798.     let elements = [];
  799.  
  800.     for (
  801.       let ir = 0;
  802.       ir < this.numberOfRows;
  803.       ir++
  804.     ) {
  805.       elements[ ir ] = [];
  806.  
  807.       for (
  808.         let ic = 0;
  809.         ic < this.numberOfColumns;
  810.         ic++
  811.       ) {
  812.         if (
  813.           ir === rowIndex
  814.         ) {
  815.           elements[ ir ][ ic ] = vector.getComponent( ic );
  816.         }
  817.         else {
  818.           elements[ ir ][ ic ] = this.elements[ ir ][ ic ];
  819.         }
  820.       } // column loop
  821.     } // row loop
  822.  
  823.     let matrix = new Matrix(
  824.       elements
  825.     );
  826.  
  827.     return matrix;
  828.   }
  829.  
  830.   // scalar
  831.   public addScalarToMatrix(
  832.     scalar: number
  833.   ): Matrix {
  834.     let elements = [];
  835.  
  836.     for (
  837.       let ir = 0;
  838.       ir < this.numberOfRows;
  839.       ir++
  840.     ) {
  841.       for (
  842.         let ic = 0;
  843.         ic < this.numberOfColumns;
  844.         ic++
  845.       ) {
  846.         elements[ ir ][ ic ] = (
  847.           this.elements[ ir ][ ic ]
  848.           + scalar
  849.         );
  850.       } // column loop
  851.     } // row loop
  852.  
  853.     let result = new Matrix(
  854.       elements
  855.     );
  856.  
  857.     return result;
  858.   }
  859.   public subtractScalarFromMatrix(
  860.     scalar: number
  861.   ): Matrix {
  862.     let elements = [];
  863.  
  864.     for (
  865.       let ir = 0;
  866.       ir < this.numberOfRows;
  867.       ir++
  868.     ) {
  869.       for (
  870.         let ic = 0;
  871.         ic < this.numberOfColumns;
  872.         ic++
  873.       ) {
  874.         elements[ ir ][ ic ] = (
  875.           this.elements[ ir ][ ic ]
  876.           - scalar
  877.         );
  878.       } // column loop
  879.     } // row loop
  880.  
  881.     let result = new Matrix(
  882.       elements
  883.     );
  884.  
  885.     return result;
  886.   }
  887.   public multiplyMatrixByScalar(
  888.     scalar: number
  889.   ): Matrix {
  890.     let elements = [];
  891.  
  892.     for (
  893.       let ir = 0;
  894.       ir < this.numberOfRows;
  895.       ir++
  896.     ) {
  897.       for (
  898.         let ic = 0;
  899.         ic < this.numberOfColumns;
  900.         ic++
  901.       ) {
  902.         elements[ ir ][ ic ] = (
  903.           this.elements[ ir ][ ic ]
  904.           * scalar
  905.         );
  906.       } // column loop
  907.     } // row loop
  908.  
  909.     let result = new Matrix(
  910.       elements
  911.     );
  912.  
  913.     return result;
  914.   }
  915.   public divideMatrixByScalar(
  916.     scalar: number
  917.   ): Matrix {
  918.     let inverseScalar = 1 / scalar;
  919.  
  920.     let result = this.multiplyMatrixByScalar(
  921.       inverseScalar
  922.     );
  923.  
  924.     return result;
  925.   }
  926.  
  927.   // vector
  928.   public addVectorToColumn(
  929.     {
  930.       columnIndex
  931.     , vector
  932.     }: {
  933.       columnIndex: number
  934.     , vector: Vector
  935.     }
  936.   ): Matrix {
  937.     this.checkElementIndex(
  938.       {
  939.         rowIndex: 0
  940.       , columnIndex: columnIndex
  941.       }
  942.     );
  943.     this.checkComponentsMatchColumns(
  944.       vector
  945.     );
  946.  
  947.     let elements = [];
  948.  
  949.     for (
  950.       let ir = 0;
  951.       ir < this.numberOfRows;
  952.       ir++
  953.     ) {
  954.       elements[ ir ] = [];
  955.  
  956.       for (
  957.         let ic = 0;
  958.         ic < this.numberOfColumns;
  959.         ic++
  960.       ) {
  961.         if (
  962.           ic === columnIndex
  963.         ) {
  964.           elements[ ir ][ ic ] = (
  965.             this.elements[ ir ][ ic ]
  966.             + vector.getComponent( ir )
  967.           );
  968.         }
  969.         else {
  970.           elements[ ir ][ ic ] = this.elements[ ir ][ ic ];
  971.         }
  972.       } // column loop
  973.     } // row loop
  974.  
  975.     let matrix = new Matrix(
  976.       elements
  977.     );
  978.  
  979.     return matrix;
  980.   }
  981.   public addVectorToRow(
  982.     {
  983.       rowIndex
  984.     , vector
  985.     }: {
  986.       rowIndex: number
  987.     , vector: Vector
  988.     }
  989.   ): Matrix {
  990.     this.checkElementIndex(
  991.       {
  992.         rowIndex: rowIndex
  993.       , columnIndex: 0
  994.       }
  995.     );
  996.     this.checkComponentsMatchRows(
  997.       vector
  998.     );
  999.  
  1000.     let elements = [];
  1001.  
  1002.     for (
  1003.       let ir = 0;
  1004.       ir < this.numberOfRows;
  1005.       ir++
  1006.     ) {
  1007.       elements[ ir ] = [];
  1008.  
  1009.       for (
  1010.         let ic = 0;
  1011.         ic < this.numberOfColumns;
  1012.         ic++
  1013.       ) {
  1014.         if (
  1015.           ir === rowIndex
  1016.         ) {
  1017.           elements[ ir ][ ic ] = (
  1018.             this.elements[ ir ][ ic ]
  1019.             + vector.getComponent( ic )
  1020.           );
  1021.         }
  1022.         else {
  1023.           elements[ ir ][ ic ] = this.elements[ ir ][ ic ];
  1024.         }
  1025.       } // column loop
  1026.     } // row loop
  1027.  
  1028.     let matrix = new Matrix(
  1029.       elements
  1030.     );
  1031.  
  1032.     return matrix;
  1033.   }
  1034.   public subtractVectorFromColumn(
  1035.     {
  1036.       columnIndex
  1037.     , vector
  1038.     }: {
  1039.       columnIndex: number
  1040.     , vector: Vector
  1041.     }
  1042.   ): Matrix {
  1043.     this.checkElementIndex(
  1044.       {
  1045.         rowIndex: 0
  1046.       , columnIndex: columnIndex
  1047.       }
  1048.     );
  1049.     this.checkComponentsMatchColumns(
  1050.       vector
  1051.     );
  1052.  
  1053.     let elements = [];
  1054.  
  1055.     for (
  1056.       let ir = 0;
  1057.       ir < this.numberOfRows;
  1058.       ir++
  1059.     ) {
  1060.       elements[ ir ] = [];
  1061.  
  1062.       for (
  1063.         let ic = 0;
  1064.         ic < this.numberOfColumns;
  1065.         ic++
  1066.       ) {
  1067.         if (
  1068.           ic === columnIndex
  1069.         ) {
  1070.           elements[ ir ][ ic ] = (
  1071.             this.elements[ ir ][ ic ]
  1072.             - vector.getComponent( ir )
  1073.           );
  1074.         }
  1075.         else {
  1076.           elements[ ir ][ ic ] = this.elements[ ir ][ ic ];
  1077.         }
  1078.       } // column loop
  1079.     } // row loop
  1080.  
  1081.     let matrix = new Matrix(
  1082.       elements
  1083.     );
  1084.  
  1085.     return matrix;
  1086.   }
  1087.   public subtractVectorFromRow(
  1088.     {
  1089.       rowIndex
  1090.     , vector
  1091.     }: {
  1092.       rowIndex: number
  1093.     , vector: Vector
  1094.     }
  1095.   ): Matrix {
  1096.     this.checkElementIndex(
  1097.       {
  1098.         rowIndex: rowIndex
  1099.       , columnIndex: 0
  1100.       }
  1101.     );
  1102.     this.checkComponentsMatchRows(
  1103.       vector
  1104.     );
  1105.  
  1106.     let elements = [];
  1107.  
  1108.     for (
  1109.       let ir = 0;
  1110.       ir < this.numberOfRows;
  1111.       ir++
  1112.     ) {
  1113.       elements[ ir ] = [];
  1114.  
  1115.       for (
  1116.         let ic = 0;
  1117.         ic < this.numberOfColumns;
  1118.         ic++
  1119.       ) {
  1120.         if (
  1121.           ir === rowIndex
  1122.         ) {
  1123.           elements[ ir ][ ic ] = (
  1124.             this.elements[ ir ][ ic ]
  1125.             - vector.getComponent( ic )
  1126.           );
  1127.         }
  1128.         else {
  1129.           elements[ ir ][ ic ] = this.elements[ ir ][ ic ];
  1130.         }
  1131.       } // column loop
  1132.     } // row loop
  1133.  
  1134.     let matrix = new Matrix(
  1135.       elements
  1136.     );
  1137.  
  1138.     return matrix;
  1139.   }
  1140.  
  1141.   public multiplyVectorByMatrix(
  1142.     vector: Vector
  1143.   ): Vector {
  1144.     this.checkComponentsMatchColumns(
  1145.       vector
  1146.     );
  1147.  
  1148.     let components = vector.getComponents();
  1149.     let resultComponents = [];
  1150.  
  1151.     for (
  1152.       let ic = 0;
  1153.       ic < this.numberOfColumns;
  1154.       ic++
  1155.     ) {
  1156.       let componentSum = 0;
  1157.      
  1158.       for (
  1159.         let ir = 0;
  1160.         ir < this.numberOfRows;
  1161.         ir++
  1162.       ) {
  1163.         componentSum = (
  1164.           componentSum
  1165.           + (
  1166.             this.elements[ ir ][ ic ]
  1167.             * components[ ic ]
  1168.           )
  1169.         );
  1170.       } // row loop
  1171.      
  1172.       resultComponents[ ic ] = componentSum;
  1173.     } // column loop
  1174.    
  1175.     let result = new Vector(
  1176.       resultComponents
  1177.     );
  1178.  
  1179.     return result;
  1180.   }
  1181.  
  1182.   // matrix
  1183.   public addMatrix(
  1184.     matrix: Matrix
  1185.   ): Matrix {
  1186.     let result = Matrix.addMatrices(
  1187.       {
  1188.         matrixA: this
  1189.       , matrixB: matrix
  1190.       }
  1191.     );
  1192.  
  1193.     return result;
  1194.   }
  1195.   public subtractMatrix(
  1196.     matrix: Matrix
  1197.   ): Matrix {
  1198.     let result = Matrix.subtractMatrices(
  1199.       {
  1200.         matrixA: this
  1201.       , matrixB: matrix
  1202.       }
  1203.     );
  1204.  
  1205.     return result;
  1206.   }
  1207.   public preMultiplyMatrix(
  1208.     matrix: Matrix
  1209.   ): Matrix {
  1210.     let result = Matrix.subtractMatrices(
  1211.       {
  1212.         matrixA: this
  1213.       , matrixB: matrix
  1214.       }
  1215.     );
  1216.  
  1217.     return result;}
  1218.   public postMultiplyMatrix(
  1219.     matrix: Matrix
  1220.   ): Matrix {
  1221.     let result = Matrix.multiplyMatrices(
  1222.       {
  1223.         matrixA: matrix,
  1224.         matrixB: this
  1225.       }
  1226.     );
  1227.  
  1228.     return result;
  1229.   }
  1230.  
  1231.   private calculateDeterminant(): void {
  1232.     if (
  1233.       !this.isSquare()
  1234.     ) {
  1235.       throw Error(
  1236.         'matrix is not square'
  1237.       );
  1238.     }
  1239.  
  1240.     let determinant;
  1241.  
  1242.     if (
  1243.       this.numberOfRows === 2
  1244.     ) {
  1245.       determinant = (
  1246.         (
  1247.           this.elements[ 0 ][ 0 ]
  1248.           * this.elements[ 1 ][ 1 ]
  1249.         )
  1250.         - (
  1251.           this.elements[ 0 ][ 1 ]
  1252.           * this.elements[ 1 ][ 0 ]
  1253.         )
  1254.       );
  1255.     }
  1256.     else {
  1257.       determinant = 0;
  1258.  
  1259.       for (
  1260.         let ic = 0;
  1261.         ic < this.numberOfColumns;
  1262.         ic++
  1263.       ) {
  1264.         determinant = (
  1265.           determinant
  1266.           + this.getCofactorFor(
  1267.             {
  1268.               rowIndex: 0,
  1269.               columnIndex: ic
  1270.             }
  1271.           )
  1272.         );
  1273.       }
  1274.     }
  1275.  
  1276.     return determinant;
  1277.   }
  1278.  
  1279.   private checkElements(
  1280.     elements: number[][]
  1281.   ): void {
  1282.     let numberOfRows = elements.length;
  1283.     let numberOfColumns = elements[ 0 ].length;
  1284.  
  1285.     Matrix.checkSize(
  1286.       {
  1287.         numberOfRows: numberOfRows
  1288.       , numberOfColumns: numberOfColumns
  1289.       }
  1290.     );
  1291.  
  1292.     for (
  1293.       let ir = 0;
  1294.       ir < numberOfRows;
  1295.       ir++
  1296.     ) {
  1297.       if (
  1298.         elements[ ir ].length !== numberOfColumns
  1299.       ) {
  1300.         throw Error(
  1301.           'column length varies across rows'
  1302.         );
  1303.       }
  1304.     } // row loop
  1305.   }
  1306.   private checkElementIndex(
  1307.     {
  1308.       rowIndex
  1309.     , columnIndex
  1310.     }: {
  1311.       rowIndex: number
  1312.     , columnIndex: number
  1313.     }
  1314.   ): void {
  1315.     if (
  1316.       columnIndex >= this.numberOfColumns
  1317.       || columnIndex < 0
  1318.       || rowIndex >= this.numberOfRows
  1319.       || rowIndex < 0
  1320.     ) {
  1321.       throw Error(
  1322.         'invalid element index'
  1323.       );
  1324.     }
  1325.   }
  1326.   private checkComponentsMatchColumns(
  1327.     vector: Vector
  1328.   ): void {
  1329.     let numberOfColumns = this.numberOfColumns;
  1330.     let numberOfComponents = vector.getNumberOfComponents();
  1331.  
  1332.     if (
  1333.       numberOfColumns !== numberOfComponents
  1334.     ) {
  1335.       throw Error(
  1336.         'matrix columns do not match number vector components'
  1337.       );
  1338.     }
  1339.   }
  1340.   private checkComponentsMatchRows(
  1341.     vector: Vector
  1342.   ): void {
  1343.     let numberOfRows = this.numberOfRows;
  1344.     let numberOfComponents = vector.getNumberOfComponents();
  1345.  
  1346.     if (
  1347.       numberOfRows !== numberOfComponents
  1348.     ) {
  1349.       throw Error(
  1350.         'matrix rows do not match number vector components'
  1351.       );
  1352.     }
  1353.   }
  1354. }
RAW Paste Data
Top