LCOV - code coverage report
Current view: top level - mentat/linalg - core.ts (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 18 807 2.2 %
Date: 2021-03-12 10:43:40 Functions: 2 48 4.2 %

          Line data    Source code
       1           1 : import * as utils from "../utils.ts";
       2             : /*
       3             : Copyright (c) 2016 Chi Feng
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : */
      23             : 
      24             : /**
      25             :  * INFO: port of the _Bayes for physicists_ linear algebra library to Deno
      26             :  */
      27           1 : export let precision = 1e-6;
      28             : 
      29             : 
      30             : export interface LUResult {
      31             :   L: Matrix;
      32             :   U: Matrix;
      33             :   P: Matrix;
      34             : }
      35             : 
      36             : export interface SVDResult {
      37             :   U: Matrix;
      38             :   S: Vector;
      39             :   V: Matrix;
      40             : }
      41             : 
      42           1 : export class Vector {
      43             :   dim: number;
      44             :   data: Float64Array;
      45           0 :   constructor(array: Array<number> | Float64Array) {
      46           0 :     this.dim = array.length;
      47           0 :     if (array instanceof Array) {
      48           0 :       this.data = new Float64Array(this.dim);
      49           0 :       for (let i = 0; i < this.dim; i++) {
      50           0 :         this.data[i] = array[i];
      51           0 :       }
      52           0 :     } else {
      53           0 :       this.data = array;
      54           0 :     }
      55           0 :   }
      56           0 :   map(f: Function): Vector {
      57           0 :     this.data = this.data.map((x) => f.apply(x));
      58           0 :     return this;
      59           0 :   }
      60             :   /**
      61             :    * Create diagonal matrix from a vector
      62             :    * @return {Float64Array} a diagonal matrix
      63             :    */
      64             : 
      65           0 :   asDiagonal(): Matrix {
      66           0 :     var D = Zeros(this.data.length, this.data.length);
      67           0 :     for (var i = 0; i < this.data.length; ++i) {
      68           0 :       D.data[i * this.data.length + i] = this.data[i];
      69           0 :     }
      70           0 :     return D;
      71           0 :   }
      72           0 :   sum(): number {
      73           0 :     var sum = 0.0;
      74           0 :     for (let i = 0; i < this.dim; i++) {
      75           0 :       sum += this.data[i];
      76           0 :     }
      77           0 :     return sum;
      78           0 :   }
      79           0 :   static zeros(n: number): Vector {
      80           0 :     let matrix = new Float64Array(n);
      81           0 :     return new Vector(matrix);
      82           0 :   }
      83           0 :   add(other: Vector | number): Vector {
      84           0 :     if (other instanceof Vector) {
      85           0 :       for (let i = 0; i < this.dim; i++) {
      86           0 :         this.data[i] += other.data[i];
      87           0 :       }
      88           0 :     } else {
      89           0 :       for (let i = 0; i < this.dim; i++) {
      90           0 :         this.data[i] += other;
      91           0 :       }
      92           0 :     }
      93           0 :     return this;
      94           0 :   }
      95           0 :   copy(): Vector {
      96           0 :     return new Vector(this.data);
      97           0 :   }
      98           1 : }
      99             : 
     100             : /**
     101             :  * Creates a "matrix" from an existing array-like object with optional dimensions
     102             :  * @param  {ArrayLike} array existing array, can be nested or flat (row-major)
     103             :  * @param  {int}       rows  number of rows
     104             :  * @param  {int}       cols  number of columns
     105             :  * @return {Float64Array}
     106             :  */
     107             : 
     108           1 : export class Matrix {
     109             :   data: Float64Array;
     110             :   rows: number;
     111             :   cols: number;
     112             :   dim: number;
     113             : 
     114           1 :   constructor(
     115           1 :     array: Array<any> | Float64Array,
     116           1 :     rows: number,
     117           1 :     cols: number,
     118             :   ) {
     119           0 :     if (array instanceof Array) {
     120           0 :       if (Array.isArray(array[0])) { // flatten nested arrays
     121           0 :         rows = array.length;
     122           0 :         cols = array[0].length;
     123           0 :         this.data = new Float64Array(rows * cols);
     124           0 :         this.rows = rows;
     125           0 :         this.cols = cols;
     126           0 :         for (var i = 0; i < rows; ++i) {
     127           0 :           for (var j = 0; j < cols; ++j) {
     128           0 :             this.data[i * cols + j] = array[i][j];
     129           0 :           }
     130           0 :         }
     131           0 :       } else {
     132           0 :         this.data = new Float64Array(array);
     133           0 :         this.rows = rows || array.length;
     134           0 :         this.cols = cols || 1;
     135           0 :       }
     136           0 :     } else {
     137           2 :       this.data = array;
     138           0 :       this.rows = rows || array.length;
     139           0 :       this.cols = cols || 1;
     140           2 :     }
     141           2 :     this.dim = this.data.length;
     142           1 :   }
     143             :   /**
     144             :  * String representation
     145             :  * @param  {int} precision (optional)
     146             :  * @return {string}
     147             :  */
     148           0 :   toString(precision: number): string {
     149           0 :     precision = precision || 4;
     150           0 :     var str = "";
     151           0 :     for (let i = 0; i < this.rows; ++i) {
     152           0 :       str += (i == 0) ? "[[ " : " [ ";
     153           0 :       str += this.data[i * this.cols + 0].toPrecision(precision);
     154           0 :       for (var j = 1; j < this.cols; ++j) {
     155           0 :         str += ", " + this.data[i * this.cols + j].toPrecision(precision);
     156           0 :       }
     157           0 :       str += (i == this.rows - 1) ? " ]]" : " ],\n";
     158           0 :     }
     159           0 :     return str;
     160           0 :   }
     161             : 
     162           0 :   asNestedArray(): Array<Array<number>> {
     163           0 :     let result: Array<Array<number>> = [];
     164           0 :     for (let i = 0; i < this.rows; i++) {
     165           0 :       result.push(Array.from(this.row(i).data));
     166           0 :     }
     167           0 :     return result;
     168           0 :   }
     169             : 
     170             :   /**
     171             :  * Returns a copy of a "matrix"
     172             :  * @return {Float64Array}
     173             :  */
     174           0 :   copy(): Matrix {
     175           0 :     var copy = new Float64Array(this.data);
     176             : 
     177           0 :     let rows = this.rows || this.data.length;
     178           0 :     let cols = this.cols || 1;
     179           0 :     return new Matrix(copy, rows, cols);
     180           0 :   }
     181             : 
     182             :   /**
     183             :  * (in place) Each element is replaced by a function applied to the element index
     184             :  * @param  {function} f takes ([i, [j]]) as arguments
     185             :  * @return {Float64Array}
     186             :  */
     187           0 :   rebuild(f: Function): Matrix {
     188           0 :     if (this.cols == 1) {
     189           0 :       for (var i = 0; i < this.rows; ++i) {
     190           0 :         this.data[i] = f(i, i);
     191           0 :       }
     192           0 :     } else {
     193           0 :       for (var i = 0; i < this.rows; ++i) {
     194           0 :         for (var j = 0; j < this.cols; ++j) {
     195           0 :           this.data[i * this.cols + j] = f(i, j);
     196           0 :         }
     197           0 :       }
     198           0 :     }
     199           0 :     return this;
     200           0 :   }
     201             : 
     202             :   /**
     203             :  * Matrix transpose (copy)
     204             :  * @return {Float64Array}
     205             :  */
     206           0 :   transpose(): Matrix {
     207           0 :     var m = this.rows, n = this.cols;
     208           0 :     var transposed = Zeros(n, m);
     209           0 :     for (var i = 0; i < m; ++i) {
     210           0 :       for (var j = 0; j < n; ++j) {
     211           0 :         transposed.data[j * m + i] = this.data[i * n + j];
     212           0 :       }
     213           0 :     }
     214           0 :     return transposed;
     215           0 :   }
     216             :   /**
     217             :  * cwise map function onto matrix copy
     218             :  * @param  {function} f arguments (A[i], i)
     219             :  * @return {Float64Array}
     220             :  */
     221           0 :   map(f: Function): Matrix {
     222           0 :     var A = Zeros(this.rows, this.cols);
     223           0 :     for (var i = 0; i < this.data.length; ++i) {
     224           0 :       A.data[i] = f(this.data[i], i);
     225           0 :     }
     226           0 :     return A;
     227           0 :   }
     228             : 
     229             :   /**
     230             :  * Add two matrices and return sum
     231             :  * @param  {Float64Array} other
     232             :  * @return {Float64Array}
     233             :  */
     234           0 :   add(other: Matrix): Matrix {
     235           0 :     if (
     236           0 :       this.cols != other.cols || this.rows != other.rows
     237           0 :     ) {
     238           0 :       throw "matrix dimension mismatch";
     239           0 :     }
     240           0 :     var sum = Zeros(this.rows, this.cols);
     241           0 :     for (var i = 0; i < this.rows; ++i) {
     242           0 :       for (var j = 0; j < this.cols; ++j) {
     243           0 :         sum.data[i * this.cols + j] = this.data[i * this.cols + j] +
     244           0 :           other.data[i * this.cols + j];
     245           0 :       }
     246           0 :     }
     247           0 :     return sum;
     248           0 :   }
     249             :   /**
     250             :  * Increment matrix (in place)
     251             :  * @param  {Float64Array} other
     252             :  * @return {Float64Array}
     253             :  */
     254           0 :   increment(other: Matrix): Matrix {
     255           0 :     if (
     256           0 :       this.cols != other.cols || this.rows != other.rows
     257           0 :     ) {
     258           0 :       throw "matrix dimension mismatch";
     259           0 :     }
     260           0 :     for (var i = 0; i < this.rows; ++i) {
     261           0 :       for (var j = 0; j < this.cols; ++j) {
     262           0 :         this.data[i * this.cols + j] += other.data[i * this.cols + j];
     263           0 :       }
     264           0 :     }
     265           0 :     return this;
     266           0 :   }
     267             : 
     268             :   /**
     269             :  * Decrement matrix (in place)
     270             :  * @param  {Float64Array} other
     271             :  * @return {Float64Array}
     272             :  */
     273           0 :   decrement(other: Matrix): Matrix {
     274           0 :     if (
     275           0 :       this.cols != other.cols || this.rows != other.rows
     276           0 :     ) {
     277           0 :       throw "matrix dimension mismatch";
     278           0 :     }
     279           0 :     for (var i = 0; i < this.rows; ++i) {
     280           0 :       for (var j = 0; j < this.cols; ++j) {
     281           0 :         this.data[i * this.cols + j] -= other.data[i * this.cols + j];
     282           0 :       }
     283           0 :     }
     284           0 :     return this;
     285           0 :   }
     286             : 
     287             :   /**
     288             :    * Subtract two matrices and return difference
     289             :    * @param  {Float64Array} other
     290             :    * @return {Float64Array}
     291             :    */
     292           0 :   subtract(other: Matrix): Matrix {
     293           0 :     if (
     294           0 :       this.cols != other.cols || this.rows != other.rows
     295           0 :     ) {
     296           0 :       throw "matrix dimension mismatch";
     297           0 :     }
     298           0 :     var difference = Zeros(this.rows, this.cols);
     299           0 :     for (var i = 0; i < this.rows; ++i) {
     300           0 :       for (var j = 0; j < this.cols; ++j) {
     301           0 :         difference.data[i * this.cols + j] = this.data[i * this.cols + j] -
     302           0 :           other.data[i * this.cols + j];
     303           0 :       }
     304           0 :     }
     305           0 :     return difference;
     306           0 :   }
     307             : 
     308             :   /**
     309             :    * Compute squared euclidian distance
     310             :    * @param  {Float64Array} other
     311             :    * @return {float}       square euclidian distance
     312             :    */
     313           0 :   dist2(other: Matrix): number {
     314           0 :     var d2 = 0;
     315           0 :     for (var i = 0; i < this.data.length; ++i) {
     316           0 :       d2 += Math.pow(this.data[i] - other.data[i], 2);
     317           0 :     }
     318           0 :     return d2;
     319           0 :   }
     320             : 
     321             :   /**
     322             :    * Compute euclidian distance
     323             :    * @param  {Float64Array} other
     324             :    * @return {float}       euclidian distance
     325             :    */
     326           0 :   dist(other: Matrix): number {
     327           0 :     return Math.sqrt(this.dist2(other));
     328           0 :   }
     329             : 
     330             :   /**
     331             :    * Multiply by scalar and return copy
     332             :    * @param  {Float64Array} scalar
     333             :    * @return {Float64Array}
     334             :    */
     335           0 :   scale(scalar: number): Matrix {
     336           0 :     var scaled = Zeros(this.rows, this.cols);
     337           0 :     for (var i = 0; i < this.rows; ++i) {
     338           0 :       for (var j = 0; j < this.cols; ++j) {
     339           0 :         scaled.data[i * this.cols + j] = scalar *
     340           0 :           this.data[i * this.cols + j];
     341           0 :       }
     342           0 :     }
     343           0 :     return scaled;
     344           0 :   }
     345             :   /**
     346             :  * cwise negate matrix copy
     347             :  * @return {Float64Array}
     348             :  */
     349           0 :   negate(): Matrix {
     350           0 :     var A = Zeros(this.rows, this.cols);
     351           0 :     for (var i = 0; i < this.data.length; ++i) {
     352           0 :       A.data[i] = -this.data[i];
     353           0 :     }
     354           0 :     return A;
     355           0 :   }
     356             : 
     357             :   /**
     358             :    * Trace of a "matrix," i.e. sum along diagonal
     359             :    * @return {float}
     360             :    */
     361           0 :   trace(): number {
     362           0 :     let diagonal = this.diagonal();
     363           0 :     var trace = 0;
     364           0 :     for (let i = 0; i < diagonal.dim; ++i) {
     365           0 :       trace += diagonal.data[i];
     366           0 :     }
     367           0 :     return trace;
     368           0 :   }
     369             : 
     370             :   /**
     371             :    * Element-wise 2-norm (Frobenius-norm for matrices)
     372             :    * @return {float}
     373             :    */
     374           0 :   norm(): number {
     375           0 :     var norm = 0;
     376           0 :     for (var i = 0; i < this.data.length; ++i) {
     377           0 :       norm += this.data[i] * this.data[i];
     378           0 :     }
     379           0 :     return Math.sqrt(norm);
     380           0 :   }
     381             : 
     382             :   /**
     383             :    * Element-wise squared norm
     384             :    * @return {float}
     385             :    */
     386           0 :   norm2(): number {
     387           0 :     var norm = 0;
     388           0 :     for (var i = 0; i < this.data.length; ++i) {
     389           0 :       norm += this.data[i] * this.data[i];
     390           0 :     }
     391           0 :     return norm;
     392           0 :   }
     393             : 
     394             :   /**
     395             :    * Sum of all elements
     396             :    * @return {float}
     397             :    */
     398           0 :   sum(): number {
     399           0 :     var sum = 0;
     400           0 :     for (var i = 0; i < this.data.length; ++i) {
     401           0 :       sum += this.data[i];
     402           0 :     }
     403           0 :     return sum;
     404           0 :   }
     405             : 
     406             :   /**
     407             :    * Get diagonal as a column vector
     408             :    * @return {Float64Array}
     409             :    */
     410           0 :   diagonal(): Vector {
     411           0 :     var diagonal = Vector.zeros(Math.min(this.rows, this.cols));
     412           0 :     for (var i = 0; i < diagonal.dim; ++i) {
     413           0 :       diagonal.data[i] = this.data[i * this.cols + i];
     414           0 :     }
     415           0 :     return diagonal;
     416           0 :   }
     417             : 
     418             :   /**
     419             :    * Get row i as a row vector
     420             :    * @param  {int} i row index
     421             :    * @return {Float64Array}
     422             :    */
     423           0 :   row(i: number): Vector {
     424           0 :     var row = Vector.zeros(this.cols);
     425           0 :     for (var j = 0; j < this.cols; ++j) {
     426           0 :       row.data[j] = this.data[i * this.cols + j];
     427           0 :     }
     428           0 :     return row;
     429           0 :   }
     430             : 
     431             :   /**
     432             :    * Get column j as as column vector
     433             :    * @param  {int} j column index
     434             :    * @return {Float64Array}
     435             :    */
     436           0 :   col(j: number): Vector {
     437           0 :     var col = Vector.zeros(this.cols);
     438           0 :     for (var i = 0; i < this.rows; ++i) {
     439           0 :       col.data[i] = this.data[i * this.cols + j];
     440           0 :     }
     441           0 :     return col;
     442           0 :   }
     443             : 
     444           0 :   setRow(i: number, row: Vector | Array<number> | Float64Array): Matrix {
     445           0 :     if (row instanceof Vector) {
     446           0 :       row = row.data;
     447           0 :     }
     448           0 :     for (var j = 0; j < this.cols; ++i) {
     449           0 :       this.data[i * this.cols + j] = row[i];
     450           0 :     }
     451           0 :     return this;
     452           0 :   }
     453             : 
     454           0 :   setCol(j: number, col: Vector | Array<number> | Float64Array): Matrix {
     455           0 :     if (col instanceof Vector) {
     456           0 :       col = col.data;
     457           0 :     }
     458           0 :     for (var i = 0; i < this.rows; ++i) {
     459           0 :       this.data[i * this.cols + j] = col[i];
     460           0 :     }
     461           0 :     return this;
     462           0 :   }
     463             : 
     464             :   /**
     465             :    * Swap rows i and k
     466             :    * @param  {int} i row index
     467             :    * @param  {int} k row index
     468             :    * @return {Float64Array} (for chaining)
     469             :    */
     470           0 :   swap_rows(i: number, k: number): Matrix {
     471           0 :     for (var j = 0; j < this.cols; ++j) {
     472           0 :       var tmp = this.data[i * this.cols + j];
     473           0 :       this.data[i * this.cols + j] = this.data[k * this.cols + j];
     474           0 :       this.data[k * this.cols + j] = tmp;
     475           0 :     }
     476           0 :     return this;
     477           0 :   }
     478             : 
     479             :   /**
     480             :    * Computes determinant using upper triangulation
     481             :    * @return {float} NaN if uninvertible
     482             :    */
     483           0 :   det(): number {
     484           0 :     if (this.rows != this.cols) throw "det() requires square matrix";
     485           0 :     if (this.rows == 2 && this.cols == 2) {
     486           0 :       return this.data[0] * this.data[3] - this.data[1] * this.data[2];
     487           0 :     }
     488             :     // upper triangularize, then return product of diagonal
     489           0 :     var U = this.copy();
     490             :     // TODO: sure about this n?
     491           0 :     let n = this.rows;
     492           0 :     for (var i = 0; i < n; ++i) {
     493           0 :       var max = 0;
     494           0 :       for (var row = i; row < n; ++row) {
     495           0 :         if (Math.abs(U.data[row * n + i]) > Math.abs(U.data[max * n + i])) {
     496           0 :           max = row;
     497           0 :         }
     498           0 :       }
     499           0 :       if (max > 0) {
     500           0 :         U.swap_rows(i, max);
     501           0 :       }
     502           0 :       if (U.data[i * n + i] == 0) return NaN;
     503           0 :       for (var row = i + 1; row < n; ++row) {
     504           0 :         var r = U.data[row * n + i] / U.data[i * n + i];
     505           0 :         if (r == 0) continue;
     506           0 :         for (var col = i; col < n; ++col);
     507           0 :         U.data[row * n + col] -= U.data[i * n + col] * r;
     508           0 :       }
     509           0 :     }
     510           0 :     var det = 1;
     511           0 :     for (var i = 0; i < n; ++i) {
     512           0 :       det *= U.data[i * n + i];
     513           0 :     }
     514           0 :     return det;
     515           0 :   }
     516             : 
     517             :   /**
     518             :    * Generalized dot product (sum of element-wise multiplication)
     519             :    * @param  {Float64Array} other another "matrix" of same size
     520             :    * @return {float}
     521             :    */
     522           0 :   dot(other: Matrix | Vector): number {
     523           0 :     var prod = 0;
     524           0 :     for (var i = 0; i < this.data.length; ++i) {
     525           0 :       prod += this.data[i] * other.data[i];
     526           0 :     }
     527           0 :     return prod;
     528           0 :   }
     529             : 
     530             :   /**
     531             :    * Matrix multiplication (naive implementation)
     532             :    * @param  {Float64Array} other
     533             :    * @return {Float64Array}
     534             :    */
     535           0 :   multiply(other: Matrix | Vector): Matrix | Vector {
     536           0 :     let A = this;
     537           0 :     let B = other;
     538           0 :     var n = A.rows;
     539           0 :     var l = A.cols;
     540           0 :     if (B instanceof Matrix) {
     541           0 :       if (A.cols != B.rows) throw "multiply() dimension mismatch";
     542           0 :       let m = B.cols;
     543           0 :       var C = Zeros(n, m);
     544           0 :       for (var i = 0; i < n; ++i) {
     545           0 :         for (var j = 0; j < m; ++j) {
     546           0 :           var cij = 0;
     547           0 :           for (var k = 0; k < l; ++k) {
     548           0 :             cij += A.data[i * l + k] * B.data[k * m + j];
     549           0 :           }
     550           0 :           C.data[i * m + j] = cij;
     551           0 :         }
     552           0 :       }
     553           0 :       return C;
     554           0 :     } else {
     555             :       // matrix-vector product
     556           0 :       let V = Vector.zeros(n);
     557           0 :       for (var i = 0; i < n; ++i) {
     558           0 :         for (var j = 0; j < l; ++j) {
     559           0 :           V.data[i] += A.data[i * l + j] * B.data[j];
     560           0 :         }
     561           0 :       }
     562           0 :       return V;
     563           0 :     }
     564             : 
     565             :     // TODO: Add to Vector
     566             :     // // vector-matrix product
     567             :     // if (n == 1) {
     568             :     //   for (var j = 0; j < m; ++j) {
     569             :     //     for (var k = 0; k < l; ++k) {
     570             :     //       C.matrix[j] += A.matrix[k] * B.matrix[k * m + j];
     571             :     //     }
     572             :     //   }
     573             :     //   return C;
     574             :     // }
     575           0 :   }
     576             : 
     577             :   /**
     578             :    * Computes PA = LU decomposition
     579             :    * @return {LUResult} {L, U, P}
     580             :    */
     581           0 :   lu(): LUResult {
     582           0 :     if (this.rows != this.cols) throw "lu() requires square matrix";
     583           0 :     var n = this.rows;
     584           0 :     var L = Zeros(n, n);
     585           0 :     var U = Zeros(n, n);
     586           0 :     var P = Eye(n);
     587           0 :     for (var j = 0; j < n; ++j) {
     588           0 :       var max = j;
     589           0 :       for (var i = j; i < n; ++i) {
     590           0 :         if (
     591           0 :           Math.abs(this.data[i * n + j]) > Math.abs(this.data[max * n + j])
     592           0 :         ) {
     593           0 :           max = i;
     594           0 :         }
     595           0 :       }
     596           0 :       if (j != max) {
     597           0 :         P.swap_rows(j, max);
     598           0 :       }
     599           0 :     }
     600           0 :     var PA = P.multiply(this);
     601           0 :     for (var j = 0; j < n; ++j) {
     602           0 :       L.data[j * n + j] = 1;
     603           0 :       for (var i = 0; i < j + 1; ++i) {
     604           0 :         var s = 0;
     605           0 :         for (var k = 0; k < i; ++k) {
     606           0 :           s += U.data[k * n + j] * L.data[i * n + k];
     607           0 :         }
     608           0 :         U.data[i * n + j] = PA.data[i * n + j] - s;
     609           0 :       }
     610           0 :       for (var i = j; i < n; ++i) {
     611           0 :         var s = 0;
     612           0 :         for (var k = 0; k < i; ++k) {
     613           0 :           s += U.data[k * n + j] * L.data[i * n + k];
     614           0 :         }
     615           0 :         L.data[i * n + j] = (PA.data[i * n + j] - s) / U.data[j * n + j];
     616           0 :       }
     617           0 :     }
     618           0 :     return { L: L, U: U, P: P };
     619           0 :   }
     620             : 
     621             :   /**
     622             :    * Cholesky A = LL^T decomposition (in-place)
     623             :    * @return {[type]} [description]
     624             :    */
     625           0 :   chol_inplace(): Matrix {
     626           0 :     if (this.rows != this.cols) throw "chol_inplace() requires square matrix";
     627           0 :     let m = this.rows;
     628           0 :     let n = this.cols;
     629           0 :     var s = 0.0;
     630           0 :     for (let i = 0; i < n; ++i) {
     631           0 :       for (let j = 0; j < (i + 1); ++j) {
     632           0 :         s = 0.0;
     633           0 :         for (let k = 0; k < j; ++k) {
     634           0 :           s += this.data[i * n + k] * this.data[j * n + k];
     635           0 :         }
     636           0 :         if (i != j) this.data[j * n + i] = 0;
     637           0 :         if (
     638           0 :           i == j && this.data[i * n + i] - s < 0
     639           0 :         ) {
     640           0 :           throw "chol_inplace() matrix not positive definite";
     641           0 :         }
     642           0 :         this.data[i * n + j] = (i == j)
     643           0 :           ? Math.sqrt(this.data[i * n + i] - s)
     644           0 :           : ((this.data[i * n + j] - s) / this.data[j * n + j]);
     645           0 :       }
     646           0 :     }
     647           0 :     return this;
     648           0 :   }
     649             : 
     650             :   /**
     651             :    * Cholesky A = LL^T decomposition (returns copy)
     652             :    * @return {Float64Array}
     653             :    */
     654           0 :   chol(): Matrix {
     655           0 :     return this.copy().chol_inplace();
     656           0 :   }
     657             : 
     658             :   /**
     659             :      * Solves Lx = b using foward substitution, updates b
     660             :      * @param  {Float64Array} b rhs
     661             :      * @return {Float64Array}
     662             :      */
     663           0 :   fsolve_inplace(b: Vector): Vector {
     664           0 :     var L = this;
     665           0 :     var m = L.rows, n = L.cols;
     666           0 :     for (var i = 0; i < n; ++i) {
     667           0 :       var s = 0.0;
     668           0 :       for (var j = 0; j < i; ++j) {
     669           0 :         s += L.data[i * n + j] * b.data[j];
     670           0 :       }
     671           0 :       b.data[i] = (b.data[i] - s) / L.data[i * n + i];
     672           0 :     }
     673           0 :     return b;
     674           0 :   }
     675             : 
     676             :   /**
     677             :      * Solves Lx = b using foward substitution
     678             :      * @param  {Float64Array} b rhs
     679             :      * @return {Float64Array}
     680             :      */
     681           0 :   fsolve(b: Vector): Vector {
     682           0 :     return this.fsolve_inplace(b.copy());
     683           0 :   }
     684             : 
     685             :   //   /**
     686             :   //    * Solves Ux = b using backward substitution, updates b
     687             :   //    * @param  {Float64Array} b rhs
     688             :   //    * @param  {object} options {transpose: false}
     689             :   //    * @return {Float64Array}
     690             :   //    */
     691             :   //   Float64Array.prototype.bsolve_inplace = function(b, options) {
     692             :   //     var U = this;
     693             :   //     var m = U.rows, n = U.cols;
     694             :   //     options = options || {};
     695             :   //     var transpose = options.hasOwnProperty('transpose') ? options.transpose : false;
     696             :   //     for (var i = n - 1; i >= 0; --i) {
     697             :   //       var s = 0.0;
     698             :   //       for (var j = i + 1; j < n; ++j)
     699             :   //         s += (transpose ? U[j * n + i] : U[i * n + j]) * b[j];
     700             :   //       b[i] = (b[i] - s) / U[i * n + i];
     701             :   //     }
     702             :   //     return b;
     703             :   //   };
     704             : 
     705             :   //   /**
     706             :   //    * Solves Ux = b using backward substitution
     707             :   //    * @param  {Float64Array} b rhs
     708             :   //    * @param  {object} options {transpose: false}
     709             :   //    * @return {Float64Array}
     710             :   //    */
     711             :   //   Float64Array.prototype.bsolve = function(b, options) {
     712             :   //     return this.bsolve_inplace(b.copy(), options);
     713             :   //   };
     714             : 
     715             :   //   /**
     716             :   //    * Solve Ax = b using PA = LU decomposition
     717             :   //    * @param  {Float64Array} b rhs
     718             :   //    * @return {Float64Array} x
     719             :   //    */
     720             :   //   Float64Array.prototype.lu_solve = function(b) {
     721             :   //     var res = this.lu(), P = res.P, L = res.L, U = res.U;
     722             :   //     return U.bsolve(L.fsolve(P.multiply(b)));
     723             :   //   };
     724             : 
     725             :   /**
     726             :      * Computes the matrix inverse using PA = LU decomposition
     727             :      * @return {Float64Array} A^-1
     728             :      */
     729           0 :   lu_inverse(): Matrix {
     730           0 :     let res = this.lu();
     731           0 :     let P = res.P;
     732           0 :     let L = res.L;
     733           0 :     let U = res.U;
     734           0 :     var inverse = Zeros(this.rows, this.cols);
     735           0 :     var eye = Eye(this.rows);
     736           0 :     for (var j = 0; j < this.cols; ++j) {
     737           0 :       let mult = P.multiply(eye.col(j)) as Vector;
     738           0 :       inverse.setCol(j, U.bsolve(L.fsolve(mult)));
     739           0 :     }
     740           0 :     return inverse;
     741           0 :   }
     742             : 
     743             :   /**
     744             :  * Solves Ux = b using backward substitution, updates b
     745             :  * @param  {Float64Array} b rhs
     746             :  * @param  {object} options {transpose: false}
     747             :  * @return {Float64Array}
     748             :  */
     749           0 :   bsolve_inplace(b: Vector, options?: any): Vector {
     750           0 :     var U = this;
     751           0 :     var m = U.rows, n = U.cols;
     752           0 :     options = options || {};
     753           0 :     var transpose = options.hasOwnProperty("transpose")
     754           0 :       ? options.transpose
     755           0 :       : false;
     756           0 :     for (var i = n - 1; i >= 0; --i) {
     757           0 :       var s = 0.0;
     758           0 :       for (var j = i + 1; j < n; ++j) {
     759           0 :         s += (transpose ? U.data[j * n + i] : U.data[i * n + j]) * b.data[j];
     760           0 :       }
     761           0 :       b.data[i] = (b.data[i] - s) / U.data[i * n + i];
     762           0 :     }
     763           0 :     return b;
     764           0 :   }
     765             : 
     766             :   /**
     767             :    * Solves Ux = b using backward substitution
     768             :    * @param  {Float64Array} b rhs
     769             :    * @param  {object} options {transpose: false}
     770             :    * @return {Float64Array}
     771             :    */
     772           0 :   bsolve(b: Vector, options?: any): Vector {
     773           0 :     return this.bsolve_inplace(b.copy(), options);
     774           0 :   }
     775             : 
     776             :   //   /**
     777             :   //    * Solve Ax = b using A = LL^T decomposition
     778             :   //    * @param  {Float64Array} b rhs
     779             :   //    * @return {Float64Array} x
     780             :   //    */
     781             :   //   Float64Array.prototype.llt_solve = function(b) {
     782             :   //     var L = this.chol();
     783             :   //     return L.bsolve(L.fsolve(b), {transpose: true});
     784             :   //   };
     785             : 
     786             :   /**
     787             :      * Computes the matrix inverse using LL^T decomposition
     788             :      * @return {Float64Array} A^-1
     789             :      */
     790           0 :   llt_inverse(): Matrix {
     791           0 :     var L = this.chol();
     792           0 :     var inverse = Zeros(this.rows, this.cols);
     793           0 :     var eye = Eye(this.rows);
     794           0 :     for (var j = 0; j < this.cols; ++j) {
     795           0 :       inverse.setCol(j, L.bsolve(L.fsolve(eye.col(j)), { transpose: true }));
     796           0 :     }
     797           0 :     return inverse;
     798           0 :   }
     799             : 
     800             :   //   /**
     801             :   //    * Solve Ax = b using A = LL^T decomposition (in-place)
     802             :   //    * @param  {Float64Array} b rhs
     803             :   //    * @return {Float64Array} x
     804             :   //    */
     805             :   //   Float64Array.prototype.llt_solve_inplace = function(b) {
     806             :   //     var L = this.chol_inplace();
     807             :   //     return L.bsolve_inplace(L.fsolve_inplace(b), {transpose: true});
     808             :   //   };
     809             : 
     810             :   //   /**
     811             :   //    * Computes diagonal matrix D of eigenvalues and matrix V whose columns are the corresponding
     812             :   //    * right eigenvectors so that AV = VD
     813             :   //    * @param  {object} options tolerance and maxIter
     814             :   //    * @return {object}         V:V D:D
     815             :   //    */
     816             :   //   Float64Array.prototype.jacobiRotation = function(options) {
     817             : 
     818             :   //     if (this.cols != this.rows) throw 'matrix must be square';
     819             : 
     820             :   //     if (arguments.length < 1)
     821             :   //       options = {};
     822             : 
     823             :   //     var maxIter = options.maxIter || 100;
     824             :   //     var tolerance = options.tolerance || 1e-5;
     825             : 
     826             :   //     var n = this.rows;
     827             :   //     var D = this.copy();
     828             :   //     var V = Float64Array.eye(n, n);
     829             : 
     830             :   //     var iter, maxOffDiag, p, q;
     831             :   //     for (iter = 0; iter < maxIter; ++iter) {
     832             : 
     833             :   //       // find max off diagonal term at (p, q)
     834             :   //       maxOffDiag = 0;
     835             :   //       for (var i = 0; i < n - 1; ++i) {
     836             :   //         for (var j = i + 1; j < n; ++j) {
     837             :   //           if (Math.abs(D[i * n + j]) > maxOffDiag) {
     838             :   //             maxOffDiag = Math.abs(D[i * n + j]);
     839             :   //             p = i; q = j;
     840             :   //           }
     841             :   //         }
     842             :   //       }
     843             : 
     844             :   //       if (maxOffDiag < tolerance)
     845             :   //         break;
     846             : 
     847             :   //       // Rotates matrix D through theta in pq-plane to set D[p][q] = 0
     848             :   //       // Rotation stored in matrix V whose columns are eigenvectors of D
     849             :   //       // d = cot 2 * theta, t = tan theta, c = cos theta, s = sin theta
     850             :   //       var d = (D[p * n + p] - D[q * n + q]) / (2.0 * D[p * n + q]);
     851             :   //       var t = Math.sign(d) / (Math.abs(d) + Math.sqrt(d * d + 1));
     852             :   //       var c = 1.0 / Math.sqrt(t * t + 1);
     853             :   //       var s = t * c;
     854             :   //       D[p * n + p] += t * D[p * n + q];
     855             :   //       D[q * n + q] -= t * D[p * n + q];
     856             :   //       D[p * n + q] =      D[q * n + p] = 0.0;
     857             :   //       for (var k = 0; k < n; k++) {  // Transform D
     858             :   //         if (k != p && k != q) {
     859             :   //           var akp =  c * D[k * n + p] + s * D[k * n + q];
     860             :   //           var akq = -s * D[k * n + p] + c * D[k * n + q];
     861             :   //           D[k * n + p] = akp;
     862             :   //           D[p * n + k] = akp;
     863             :   //           D[k * n + q] = akq;
     864             :   //           D[q * n + k] = akq;
     865             :   //         }
     866             :   //       }
     867             :   //       for (var k = 0; k < n; k++) {  // Store V
     868             :   //         var rkp =  c * V[k * n + p] + s * V[k * n + q];
     869             :   //         var rkq = -s * V[k * n + p] + c * V[k * n + q];
     870             :   //         V[k * n + p] = rkp;
     871             :   //         V[k * n + q] = rkq;
     872             :   //       }
     873             :   //     }
     874             : 
     875             :   //     if (iter == maxIter) {
     876             :   //       console.log('Hit maxIter: ', maxOffDiag, ' > ', tolerance);
     877             :   //     }
     878             : 
     879             :   //     return {V:V, D:D, eigenvalues: D.diagonal(), eigenvectors: V};
     880             : 
     881             :   //   };
     882             : 
     883             :   //   Float64Array.prototype.maxCoeff = function() {
     884             :   //     var max = this[0];
     885             :   //     for (var i = 0; i < this.length; ++i) {
     886             :   //       if (this[i] > max)
     887             :   //         max = this[i];
     888             :   //     }
     889             :   //     return max;
     890             :   //   };
     891             : 
     892             :   //   Float64Array.prototype.cwiseProduct = function(other) {
     893             :   //     var A = this.copy();
     894             :   //     for (var i = 0; i < this.length; ++i) {
     895             :   //       A[i] = this[i] * other[i];
     896             :   //     }
     897             :   //     return A;
     898             :   //   };
     899             : 
     900             :   //   Float64Array.prototype.cwiseQuotient = function(other) {
     901             :   //     var A = this.copy();
     902             :   //     for (var i = 0; i < this.length; ++i) {
     903             :   //       A[i] = this[i] / other[i];
     904             :   //     }
     905             :   //     return A;
     906             :   //   };
     907             : 
     908             :   //   Float64Array.prototype.cwiseInverse = function() {
     909             :   //     var A = this.copy();
     910             :   //     for (var i = 0; i < this.length; ++i) {
     911             :   //       A[i] = 1.0 / this[i];
     912             :   //     }
     913             :   //     return A;
     914             :   //   };
     915             : 
     916             :   //   Float64Array.prototype.cwiseSqrt = function() {
     917             :   //     var A = this.copy();
     918             :   //     for (var i = 0; i < this.length; ++i) {
     919             :   //       A[i] = Math.sqrt(this[i]);
     920             :   //     }
     921             :   //     return A;
     922             :   //   };
     923             : 
     924             :   /*
     925             : Shanti Rao sent me this routine by private email. I had to modify it
     926             : slightly to work on Arrays instead of using a Matrix object.
     927             : It is apparently translated from http://stitchpanorama.sourceforge.net/Python/svd.py
     928             :   */
     929             : 
     930           0 :   svd(): SVDResult {
     931           0 :     let A = this;
     932           0 :     var temp;
     933             :     //Compute the thin SVD from G. H. Golub and C. Reinsch, Numer. Math. 14, 403-420 (1970)
     934           0 :     var prec = Math.pow(2, -52); // assumes double prec
     935           0 :     var tolerance = 1.e-64 / prec;
     936           0 :     var itmax = 50;
     937           0 :     var c = 0;
     938           0 :     var i = 0;
     939           0 :     var j = 0;
     940           0 :     var k = 0;
     941           0 :     var l = 0;
     942             : 
     943           0 :     var u = A.copy().asNestedArray();
     944           0 :     var m = u.length;
     945             : 
     946           0 :     var n = u[0].length;
     947             : 
     948           0 :     if (m < n) throw "Need more rows than columns";
     949             : 
     950           0 :     var e = new Array(n);
     951           0 :     var q: Array<number> = new Array(n);
     952           0 :     for (i = 0; i < n; i++) e[i] = q[i] = 0.0;
     953           0 :     var v: Array<Array<number>> = utils.rep([n, n], 0);
     954             :     //  v.zero();
     955             : 
     956           0 :     let pythag = (a: number, b: number) => {
     957           0 :       a = Math.abs(a);
     958           0 :       b = Math.abs(b);
     959           0 :       if (a > b) {
     960           0 :         return a * Math.sqrt(1.0 + (b * b / a / a));
     961           0 :       } else if (b == 0.0) {
     962           0 :         return a;
     963           0 :       }
     964           0 :       return b * Math.sqrt(1.0 + (a * a / b / b));
     965           0 :     };
     966             : 
     967             :     //Householder's reduction to bidiagonal form
     968             : 
     969           0 :     var f = 0.0;
     970           0 :     var g = 0.0;
     971           0 :     var h = 0.0;
     972           0 :     var x = 0.0;
     973           0 :     var y = 0.0;
     974           0 :     var z = 0.0;
     975           0 :     var s = 0.0;
     976             : 
     977           0 :     for (i = 0; i < n; i++) {
     978           0 :       e[i] = g;
     979           0 :       s = 0.0;
     980           0 :       l = i + 1;
     981           0 :       for (j = i; j < m; j++) {
     982           0 :         s += (u[j][i] * u[j][i]);
     983           0 :       }
     984           0 :       if (s <= tolerance) {
     985           0 :         g = 0.0;
     986           0 :       } else {
     987           0 :         f = u[i][i];
     988           0 :         g = Math.sqrt(s);
     989           0 :         if (f >= 0.0) g = -g;
     990           0 :         h = f * g - s;
     991           0 :         u[i][i] = f - g;
     992           0 :         for (j = l; j < n; j++) {
     993           0 :           s = 0.0;
     994           0 :           for (k = i; k < m; k++) {
     995           0 :             s += u[k][i] * u[k][j];
     996           0 :           }
     997           0 :           f = s / h;
     998           0 :           for (k = i; k < m; k++) {
     999           0 :             u[k][j] += f * u[k][i];
    1000           0 :           }
    1001           0 :         }
    1002           0 :       }
    1003           0 :       q[i] = g;
    1004           0 :       s = 0.0;
    1005           0 :       for (j = l; j < n; j++) {
    1006           0 :         s = s + u[i][j] * u[i][j];
    1007           0 :       }
    1008           0 :       if (s <= tolerance) {
    1009           0 :         g = 0.0;
    1010           0 :       } else {
    1011           0 :         f = u[i][i + 1];
    1012           0 :         g = Math.sqrt(s);
    1013           0 :         if (f >= 0.0) g = -g;
    1014           0 :         h = f * g - s;
    1015           0 :         u[i][i + 1] = f - g;
    1016           0 :         for (j = l; j < n; j++) e[j] = u[i][j] / h;
    1017           0 :         for (j = l; j < m; j++) {
    1018           0 :           s = 0.0;
    1019           0 :           for (k = l; k < n; k++) {
    1020           0 :             s += (u[j][k] * u[i][k]);
    1021           0 :           }
    1022           0 :           for (k = l; k < n; k++) {
    1023           0 :             u[j][k] += s * e[k];
    1024           0 :           }
    1025           0 :         }
    1026           0 :       }
    1027           0 :       y = Math.abs(q[i]) + Math.abs(e[i]);
    1028           0 :       if (y > x) {
    1029           0 :         x = y;
    1030           0 :       }
    1031           0 :     }
    1032             : 
    1033             :     // accumulation of right hand gtransformations
    1034           0 :     for (i = n - 1; i != -1; i += -1) {
    1035           0 :       if (g != 0.0) {
    1036           0 :         h = g * u[i][i + 1];
    1037           0 :         for (j = l; j < n; j++) {
    1038           0 :           v[j][i] = u[i][j] / h;
    1039           0 :         }
    1040           0 :         for (j = l; j < n; j++) {
    1041           0 :           s = 0.0;
    1042           0 :           for (k = l; k < n; k++) {
    1043           0 :             s += u[i][k] * v[k][j];
    1044           0 :           }
    1045           0 :           for (k = l; k < n; k++) {
    1046           0 :             v[k][j] += (s * v[k][i]);
    1047           0 :           }
    1048           0 :         }
    1049           0 :       }
    1050           0 :       for (j = l; j < n; j++) {
    1051           0 :         v[i][j] = 0;
    1052           0 :         v[j][i] = 0;
    1053           0 :       }
    1054           0 :       v[i][i] = 1;
    1055           0 :       g = e[i];
    1056           0 :       l = i;
    1057           0 :     }
    1058             : 
    1059             :     // accumulation of left hand transformations
    1060           0 :     for (i = n - 1; i != -1; i += -1) {
    1061           0 :       l = i + 1;
    1062           0 :       g = q[i];
    1063           0 :       for (j = l; j < n; j++) {
    1064           0 :         u[i][j] = 0;
    1065           0 :       }
    1066           0 :       if (g != 0.0) {
    1067           0 :         h = u[i][i] * g;
    1068           0 :         for (j = l; j < n; j++) {
    1069           0 :           s = 0.0;
    1070           0 :           for (k = l; k < m; k++) s += u[k][i] * u[k][j];
    1071           0 :           f = s / h;
    1072           0 :           for (k = i; k < m; k++) u[k][j] += f * u[k][i];
    1073           0 :         }
    1074           0 :         for (j = i; j < m; j++) u[j][i] = u[j][i] / g;
    1075           0 :       } else {
    1076           0 :         for (j = i; j < m; j++) u[j][i] = 0;
    1077           0 :       }
    1078           0 :       u[i][i] += 1;
    1079           0 :     }
    1080             : 
    1081             :     // diagonalization of the bidiagonal form
    1082           0 :     prec = prec * x;
    1083           0 :     for (k = n - 1; k != -1; k += -1) {
    1084           0 :       for (var iteration = 0; iteration < itmax; iteration++) { // test f splitting
    1085           0 :         var test_convergence = false;
    1086           0 :         for (l = k; l != -1; l += -1) {
    1087           0 :           if (Math.abs(e[l]) <= prec) {
    1088           0 :             test_convergence = true;
    1089           0 :             break;
    1090           0 :           }
    1091           0 :           if (Math.abs(q[l - 1]) <= prec) {
    1092           0 :             break;
    1093           0 :           }
    1094           0 :         }
    1095           0 :         if (!test_convergence) { // cancellation of e[l] if l>0
    1096           0 :           c = 0.0;
    1097           0 :           s = 1.0;
    1098           0 :           var l1 = l - 1;
    1099           0 :           for (i = l; i < k + 1; i++) {
    1100           0 :             f = s * e[i];
    1101           0 :             e[i] = c * e[i];
    1102           0 :             if (Math.abs(f) <= prec) {
    1103           0 :               break;
    1104           0 :             }
    1105           0 :             g = q[i];
    1106           0 :             h = pythag(f, g);
    1107           0 :             q[i] = h;
    1108           0 :             c = g / h;
    1109           0 :             s = -f / h;
    1110           0 :             for (j = 0; j < m; j++) {
    1111           0 :               y = u[j][l1];
    1112           0 :               z = u[j][i];
    1113           0 :               u[j][l1] = y * c + (z * s);
    1114           0 :               u[j][i] = -y * s + (z * c);
    1115           0 :             }
    1116           0 :           }
    1117           0 :         }
    1118             :         // test f convergence
    1119           0 :         z = q[k];
    1120           0 :         if (l == k) { //convergence
    1121           0 :           if (z < 0.0) { //q[k] is made non-negative
    1122           0 :             q[k] = -z;
    1123           0 :             for (j = 0; j < n; j++) {
    1124           0 :               v[j][k] = -v[j][k];
    1125           0 :             }
    1126           0 :           }
    1127           0 :           break; //break out of iteration loop and move on to next k value
    1128           0 :         }
    1129           0 :         if (iteration >= itmax - 1) {
    1130           0 :           throw "Error: no convergence.";
    1131           0 :         }
    1132             :         // shift from bottom 2x2 minor
    1133           0 :         x = q[l];
    1134           0 :         y = q[k - 1];
    1135           0 :         g = e[k - 1];
    1136           0 :         h = e[k];
    1137           0 :         f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);
    1138           0 :         g = pythag(f, 1.0);
    1139           0 :         if (f < 0.0) {
    1140           0 :           f = ((x - z) * (x + z) + h * (y / (f - g) - h)) / x;
    1141           0 :         } else {
    1142           0 :           f = ((x - z) * (x + z) + h * (y / (f + g) - h)) / x;
    1143           0 :         }
    1144             :         // next QR transformation
    1145           0 :         c = 1.0;
    1146           0 :         s = 1.0;
    1147           0 :         for (i = l + 1; i < k + 1; i++) {
    1148           0 :           g = e[i];
    1149           0 :           y = q[i];
    1150           0 :           h = s * g;
    1151           0 :           g = c * g;
    1152           0 :           z = pythag(f, h);
    1153           0 :           e[i - 1] = z;
    1154           0 :           c = f / z;
    1155           0 :           s = h / z;
    1156           0 :           f = x * c + g * s;
    1157           0 :           g = -x * s + g * c;
    1158           0 :           h = y * s;
    1159           0 :           y = y * c;
    1160           0 :           for (j = 0; j < n; j++) {
    1161           0 :             x = v[j][i - 1];
    1162           0 :             z = v[j][i];
    1163           0 :             v[j][i - 1] = x * c + z * s;
    1164           0 :             v[j][i] = -x * s + z * c;
    1165           0 :           }
    1166           0 :           z = pythag(f, h);
    1167           0 :           q[i - 1] = z;
    1168           0 :           c = f / z;
    1169           0 :           s = h / z;
    1170           0 :           f = c * g + s * y;
    1171           0 :           x = -s * g + c * y;
    1172           0 :           for (j = 0; j < m; j++) {
    1173           0 :             y = u[j][i - 1];
    1174           0 :             z = u[j][i];
    1175           0 :             u[j][i - 1] = y * c + z * s;
    1176           0 :             u[j][i] = -y * s + z * c;
    1177           0 :           }
    1178           0 :         }
    1179           0 :         e[l] = 0.0;
    1180           0 :         e[k] = f;
    1181           0 :         q[k] = x;
    1182           0 :       }
    1183           0 :     }
    1184             : 
    1185             :     //vt= transpose(v)
    1186             :     //return (u,q,vt)
    1187           0 :     for (i = 0; i < q.length; i++) {
    1188           0 :       if (q[i] < prec) q[i] = 0;
    1189           0 :     }
    1190             : 
    1191             :     //sort eigenvalues
    1192           0 :     for (i = 0; i < n; i++) {
    1193             :       //writeln(q)
    1194           0 :       for (j = i - 1; j >= 0; j--) {
    1195           0 :         if (q[j] < q[i]) {
    1196             :           //  writeln(i,'-',j)
    1197           0 :           c = q[j];
    1198           0 :           q[j] = q[i];
    1199           0 :           q[i] = c;
    1200           0 :           for (k = 0; k < u.length; k++) {
    1201           0 :             temp = u[k][i];
    1202           0 :             u[k][i] = u[k][j];
    1203           0 :             u[k][j] = temp;
    1204           0 :           }
    1205           0 :           for (k = 0; k < v.length; k++) {
    1206           0 :             temp = v[k][i];
    1207           0 :             v[k][i] = v[k][j];
    1208           0 :             v[k][j] = temp;
    1209           0 :           }
    1210             :           //       u.swapCols(i,j)
    1211             :           //       v.swapCols(i,j)
    1212           0 :           i = j;
    1213           0 :         }
    1214           0 :       }
    1215           0 :     }
    1216             : 
    1217           0 :     let U = new Matrix(u, this.rows, this.cols);
    1218           0 :     console.log(`u: ${u}`);
    1219           0 :     console.log(`q: ${q}`);
    1220           0 :     console.log(`v: ${v}`);
    1221           0 :     let S = new Vector(q);
    1222           0 :     let V = new Matrix(v, this.rows, this.cols);
    1223             : 
    1224           0 :     return { U: U, S: S, V: V };
    1225           0 :   }
    1226           1 : }
    1227             : 
    1228             : /**
    1229             :  * Creates a "matrix" with all entries set to zero
    1230             :  * @param  {int} rows number of rows
    1231             :  * @param  {int} cols number of columns
    1232             :  * @return {Float64Array}
    1233             :  */
    1234           1 : export function Zeros(rows: number, cols: number): Matrix {
    1235           0 :   cols = cols || 1;
    1236           2 :   var matrix = new Float64Array(rows * cols);
    1237           2 :   return new Matrix(matrix, rows, cols);
    1238           1 : }
    1239             : 
    1240             : /**
    1241             :  * Creates a column vector with linearly-spaced elements
    1242             :  * @param  {float} min minimum value (inclusive)
    1243             :  * @param  {float} max maximum value (inclusive)
    1244             :  * @param  {int}   n   number of elements
    1245             :  * @return {Float64Array}
    1246             :  */
    1247           0 : export function Linspace(min: number, max: number, n: number): Float64Array {
    1248           0 :   var matrix = new Float64Array(n);
    1249           0 :   var dx = (max - min) / (n - 1);
    1250           0 :   for (var i = 0; i < n; ++i) {
    1251           0 :     matrix[i] = i * dx + min;
    1252           0 :   }
    1253           0 :   return matrix;
    1254           0 : }
    1255             : 
    1256             : /**
    1257             :  * Creates a n x n identity matrix
    1258             :  * @param  {int} n number of rows and columns
    1259             :  * @return {Float64Array}
    1260             :  *
    1261             :  *     const n = 3;
    1262             :  *     const diagonal = Eye(n);
    1263             :  */
    1264           0 : export function Eye(n: number): Matrix {
    1265           0 :   var matrix = new Float64Array(n * n);
    1266           0 :   for (var i = 0; i < n; ++i) {
    1267           0 :     matrix[i * n + i] = 1;
    1268           0 :   }
    1269           0 :   return new Matrix(matrix, n, n);
    1270           0 : } /**
    1271             :  * Creates a "matrix" filled with ones
    1272             :  * @param  {int} rows number of rows
    1273             :  * @param  {int} cols number of columns
    1274             :  * @return {Float64Array}
    1275             :  */
    1276             : 
    1277           0 : export function Ones(rows: number, cols: number): Matrix {
    1278           0 :   cols = cols || 1;
    1279           0 :   var matrix = new Float64Array(rows * cols);
    1280           0 :   for (var i = 0; i < matrix.length; ++i) {
    1281           0 :     matrix[i] = 1;
    1282           0 :   }
    1283           0 :   return new Matrix(matrix, rows, cols);
    1284           0 : } /**
    1285             :  * Creates a "matrix" filled with constant
    1286             :  * @param  {float} const constant
    1287             :  * @param  {int}   rows number of rows
    1288             :  * @param  {int}   cols number of columns
    1289             :  * @return {Float64Array}
    1290             :  */
    1291             : 
    1292           0 : export function Constant(constant: number, rows: number, cols: number): Matrix {
    1293           0 :   cols = cols || 1;
    1294           0 :   var matrix = new Float64Array(rows * cols);
    1295           0 :   for (var i = 0; i < matrix.length; ++i) {
    1296           0 :     matrix[i] = constant;
    1297           0 :   }
    1298           0 :   return new Matrix(matrix, rows, cols);
    1299           0 : } /**
    1300             :  * Build a "matrix" where each element is a function applied to element index
    1301             :  * @param  {function} f    takes ([i, [j]]) as arguments
    1302             :  * @param  {int}      rows number of rows
    1303             :  * @param  {int}      cols number of cols
    1304             :  * @return {Float64Array}
    1305             :  */
    1306             : 
    1307           0 : export function Build(f: Function, rows: number, cols: number) {
    1308           0 :   cols = cols || 1;
    1309           0 :   var matrix = Zeros(rows, cols);
    1310           0 :   for (var i = 0; i < rows; ++i) {
    1311           0 :     for (var j = 0; j < cols; ++j) {
    1312           0 :       matrix.data[i * cols + j] = f(i, j);
    1313           0 :     }
    1314           0 :   }
    1315           0 :   return new Matrix(matrix.data, rows, cols);
    1316           0 : } /**
    1317             :  * Outer product (form matrix from vector tensor product)
    1318             :  * @param  {Float64Array} u vector (column or row)
    1319             :  * @param  {Float64Array} v vector (column or row)
    1320             :  * @return {Float64Array}
    1321             :  */
    1322             : 
    1323           0 : export function Outer(u: Float64Array, v: Float64Array) {
    1324           0 :   var A = Zeros(u.length, v.length);
    1325           0 :   for (var i = 0; i < u.length; ++i) {
    1326           0 :     for (var j = 0; j < v.length; ++j) {
    1327           0 :       A.data[i * v.length + j] = u[i] * v[j];
    1328           0 :     }
    1329           0 :   }
    1330           0 :   return A;
    1331           0 : }

Generated by: LCOV version 1.15