001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.math.matrix; 031 032import java.io.PrintWriter; 033import java.io.StringWriter; 034import java.util.Random; 035 036import no.uib.cipr.matrix.DenseMatrix; 037import no.uib.cipr.matrix.NotConvergedException; 038import no.uib.cipr.matrix.SVD; 039import Jama.EigenvalueDecomposition; 040import Jama.Matrix; 041import ch.akuhn.matrix.SparseMatrix; 042 043/** 044 * Miscellaneous matrix operations. 045 * 046 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 047 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 048 * 049 */ 050public class MatrixUtils { 051 private MatrixUtils() { 052 } 053 054 /** 055 * Are any values NaN or Inf? 056 * 057 * @param matrix 058 * matrix to test 059 * @return true if any elements are NaN or Inf; false otherwise 060 */ 061 public static boolean anyNaNorInf(Matrix matrix) { 062 for (final double[] arrLine : matrix.getArray()) { 063 for (final double d : arrLine) { 064 if (Double.isNaN(d) || Double.isInfinite(d)) 065 return true; 066 } 067 } 068 return false; 069 } 070 071 /** 072 * Get the maximum absolute value of the diagonal. 073 * 074 * @param matrix 075 * the matrix 076 * @return the maximum absolute value 077 */ 078 public static double maxAbsDiag(Matrix matrix) { 079 double max = -1; 080 081 for (int i = 0; i < matrix.getColumnDimension(); i++) { 082 final double curr = Math.abs(matrix.get(i, i)); 083 if (max < curr) { 084 max = curr; 085 } 086 } 087 return max; 088 } 089 090 /** 091 * Get the minimum absolute value of the diagonal. 092 * 093 * @param matrix 094 * the matrix 095 * @return the minimum absolute value 096 */ 097 public static double minAbsDiag(Matrix matrix) { 098 double min = Double.MAX_VALUE; 099 100 for (int i = 0; i < matrix.getColumnDimension(); i++) { 101 final double curr = Math.abs(matrix.get(i, i)); 102 if (min > curr) { 103 min = curr; 104 } 105 } 106 return min; 107 } 108 109 /** 110 * Compute the principle square root, X, of the matrix A such that A=X*X 111 * 112 * @param matrix 113 * the matrix 114 * @return the sqrt of the matrix 115 */ 116 public static Matrix sqrt(Matrix matrix) { 117 // A = V*D*V' 118 final EigenvalueDecomposition evd = matrix.eig(); 119 final Matrix v = evd.getV(); 120 final Matrix d = evd.getD(); 121 122 // sqrt of cells of D and store in-place 123 for (int r = 0; r < d.getRowDimension(); r++) 124 for (int c = 0; c < d.getColumnDimension(); c++) 125 d.set(r, c, Math.sqrt(d.get(r, c))); 126 127 // Y = V*D/V 128 // Y = V'.solve(V*D)' 129 final Matrix a = v.inverse(); 130 final Matrix b = v.times(d).inverse(); 131 return a.solve(b).inverse(); 132 } 133 134 /** 135 * Computes the Moore-Penrose pseudoinverse. This is just a convenience 136 * wrapper around {@link PseudoInverse#pseudoInverse(Matrix)}. 137 * 138 * @param matrix 139 * the matrix to invert. 140 * @return the inverted matrix 141 * @see PseudoInverse#pseudoInverse(Matrix) 142 */ 143 public static Matrix pseudoInverse(Matrix matrix) { 144 return PseudoInverse.pseudoInverse(matrix); 145 } 146 147 /** 148 * Compute the inverse square root, X, of the symmetric matrix A; A^-(1/2) 149 * 150 * @param matrix 151 * the symmetric matrix 152 * @return the inverse sqrt of the matrix 153 */ 154 public static Matrix invSqrtSym(Matrix matrix) { 155 // A = V*D*V' 156 final EigenvalueDecomposition evd = matrix.eig(); 157 final Matrix v = evd.getV(); 158 final Matrix d = evd.getD(); 159 160 // sqrt of cells of D and store in-place 161 for (int r = 0; r < d.getRowDimension(); r++) { 162 for (int c = 0; c < d.getColumnDimension(); c++) { 163 if (d.get(r, c) > 0) 164 d.set(r, c, 1 / Math.sqrt(d.get(r, c))); 165 else 166 d.set(r, c, 0); 167 } 168 } 169 170 return v.times(d).times(v.transpose()); 171 } 172 173 /** 174 * Return a copy of the input matrix with all elements set to their absolute 175 * value. 176 * 177 * @param mat 178 * the matrix. 179 * @return the absolute matrix. 180 */ 181 public static Matrix abs(Matrix mat) { 182 final Matrix copy = mat.copy(); 183 for (int i = 0; i < mat.getRowDimension(); i++) { 184 for (int j = 0; j < mat.getColumnDimension(); j++) { 185 copy.set(i, j, Math.abs(mat.get(i, j))); 186 } 187 } 188 return copy; 189 } 190 191 /** 192 * Check if two matrices are equal 193 * 194 * @param m1 195 * first matrix 196 * @param m2 197 * second matrix 198 * @param eps 199 * epsilon for checking values 200 * @return true if matrices have same size and all elements are equal within 201 * eps; false otherwise 202 */ 203 public static boolean equals(Matrix m1, Matrix m2, double eps) { 204 final double[][] a1 = m1.getArray(); 205 final double[][] a2 = m2.getArray(); 206 207 if (a1.length != a2.length || a1[0].length != a2[0].length) 208 return false; 209 210 for (int r = 0; r < a1.length; r++) 211 for (int c = 0; c < a1[r].length; c++) 212 if (Math.abs(a1[r][c] - a2[r][c]) > eps) 213 return false; 214 215 return true; 216 } 217 218 /** 219 * Return a copy of the matrix with all the values raised to a power. 220 * 221 * @param mat 222 * the matrix. 223 * @param exp 224 * the power. 225 * @return a matrix. 226 */ 227 public static Matrix pow(Matrix mat, double exp) { 228 final Matrix copy = mat.copy(); 229 for (int i = 0; i < mat.getRowDimension(); i++) { 230 for (int j = 0; j < mat.getColumnDimension(); j++) { 231 copy.set(i, j, Math.pow(mat.get(i, j), exp)); 232 } 233 } 234 return copy; 235 } 236 237 /** 238 * Generate a {@link String} representation of a matrix. 239 * 240 * @param mat 241 * the matrix 242 * @return a string representation 243 */ 244 public static String toString(Matrix mat) { 245 final StringWriter matWriter = new StringWriter(); 246 mat.print(new PrintWriter(matWriter), 5, 5); 247 return matWriter.getBuffer().toString(); 248 } 249 250 /** 251 * Compute the sum of all elements of the matrix. 252 * 253 * @param mat 254 * the matrix. 255 * @return the sum. 256 */ 257 public static double sum(Matrix mat) { 258 double sum = 0; 259 for (int i = 0; i < mat.getRowDimension(); i++) { 260 for (int j = 0; j < mat.getColumnDimension(); j++) { 261 sum += mat.get(i, j); 262 } 263 } 264 return sum; 265 } 266 267 /** 268 * Zero the matrix 269 * 270 * @param m 271 * the matrix 272 */ 273 public static void zero(Matrix m) { 274 m.timesEquals(0); 275 } 276 277 /** 278 * Compute the real Eigen decomposition of a symmetric 2x2 matrix. Warning: 279 * Doesn't check the size or whether the input is symmetric. 280 * 281 * @param m 282 * the matrix 283 * @return the Eigen vectors and values. 284 */ 285 public static EigenValueVectorPair symmetricEig2x2(Matrix m) { 286 final double a = m.get(0, 0); 287 final double b = m.get(0, 1); 288 final double c = b; 289 final double d = m.get(1, 1); 290 291 final double trace = a + d; 292 final double det = a * d - b * c; 293 294 final Matrix val = new Matrix(2, 2); 295 double sqrtInner = (trace * trace / 4) - det; 296 // FIXME: make it deal with imaginary numbers. 297 if (sqrtInner < 0) { 298 final EigenvalueDecomposition e = m.eig(); 299 return new EigenValueVectorPair(e.getD(), e.getV()); 300 } 301 302 sqrtInner = Math.sqrt(sqrtInner); 303 double firstEig = trace / 2 + sqrtInner; 304 double secondEig = trace / 2 - sqrtInner; 305 if (firstEig > secondEig) { 306 final double tmp = firstEig; 307 firstEig = secondEig; 308 secondEig = tmp; 309 } 310 311 val.set(0, 0, firstEig); 312 val.set(1, 1, secondEig); 313 314 final Matrix vec = new Matrix(2, 2); 315 316 final double v1 = firstEig - a; 317 final double v2 = secondEig - a; 318 final double norm1 = Math.sqrt(v1 * v1 + b * b); 319 final double norm2 = Math.sqrt(b * b + v2 * v2); 320 vec.set(0, 0, b / norm1); 321 vec.set(0, 1, b / norm2); 322 vec.set(1, 0, v1 / norm1); 323 vec.set(1, 1, v2 / norm2); 324 325 // To deal with rounding error 326 vec.set(1, 0, vec.get(0, 1)); 327 328 final EigenValueVectorPair ret = new EigenValueVectorPair(val, vec); 329 return ret; 330 } 331 332 /** 333 * An eigen decomposition that uses a deterministic method if the matrix is 334 * 2x2. 335 * 336 * This function returns values as in {@link EigenvalueDecomposition} i.e. 337 * the largest eigen value is held in the [m.rows - 1,m.cols-1] (i.e. [1,1]) 338 * location 339 * 340 * @param m 341 * @return the decomposition 342 */ 343 public static EigenValueVectorPair eig2x2(Matrix m) { 344 if (m.getColumnDimension() != 2 || m.getRowDimension() != 2) { 345 final EigenvalueDecomposition e = m.eig(); 346 return new EigenValueVectorPair(e.getD(), e.getV()); 347 } 348 /** 349 * A = 1 B = a + d C = ad - bc 350 * 351 * x = ( - B (+/-) sqrt(B^2 - 4AC) )/ (2A) 352 */ 353 final double a = m.get(0, 0); 354 final double b = m.get(0, 1); 355 final double c = m.get(1, 0); 356 final double d = m.get(1, 1); 357 358 final double trace = a + d; 359 final double det = a * d - b * c; 360 361 final Matrix val = new Matrix(2, 2); 362 double sqrtInner = (trace * trace / 4) - det; 363 // FIXME: make it deal with imaginary numbers. 364 if (sqrtInner < 0) { 365 final EigenvalueDecomposition e = m.eig(); 366 return new EigenValueVectorPair(e.getD(), e.getV()); 367 } 368 369 sqrtInner = Math.sqrt(sqrtInner); 370 double firstEig = trace / 2 + sqrtInner; 371 double secondEig = trace / 2 - sqrtInner; 372 if (firstEig > secondEig) { 373 final double tmp = firstEig; 374 firstEig = secondEig; 375 secondEig = tmp; 376 } 377 378 val.set(0, 0, firstEig); 379 val.set(1, 1, secondEig); 380 381 final Matrix vec = new Matrix(2, 2); 382 if (b == 0 && c == 0) { 383 vec.set(0, 0, 1); 384 vec.set(1, 1, 1); 385 } else { 386 if (c != 0) { 387 final double v1 = firstEig - d; 388 final double v2 = secondEig - d; 389 final double norm1 = Math.sqrt(v1 * v1 + c * c); 390 final double norm2 = Math.sqrt(c * c + v2 * v2); 391 vec.set(0, 0, v1 / norm1); 392 vec.set(0, 1, v2 / norm2); 393 vec.set(1, 0, c / norm1); 394 vec.set(1, 1, c / norm2); 395 } else if (b != 0) { 396 final double v1 = firstEig - a; 397 final double v2 = secondEig - a; 398 final double norm1 = Math.sqrt(v1 * v1 + b * b); 399 final double norm2 = Math.sqrt(b * b + v2 * v2); 400 vec.set(0, 0, b / norm1); 401 vec.set(0, 1, b / norm2); 402 vec.set(1, 0, v1 / norm1); 403 vec.set(1, 1, v2 / norm2); 404 } 405 } 406 407 final EigenValueVectorPair ret = new EigenValueVectorPair(val, vec); 408 return ret; 409 } 410 411 /** 412 * Construct a matrix from a 2D float array of data. 413 * 414 * @param data 415 * the data. 416 * @return the matrix. 417 */ 418 public static Matrix matrixFromFloat(float[][] data) { 419 final Matrix out = new Matrix(data.length, data[0].length); 420 for (int i = 0; i < data.length; i++) { 421 for (int j = 0; j < data[i].length; j++) { 422 out.set(j, i, data[i][j]); 423 } 424 } 425 return out; 426 } 427 428 /** 429 * Reduce the rank a matrix by estimating a the best (in a least-squares 430 * sense) approximation using the thin SVD. 431 * 432 * @param m 433 * the matrix to reduce. 434 * @param rank 435 * the desired rank. 436 * @return the rank-reduced matrix. 437 */ 438 public static Matrix reduceRank(Matrix m, int rank) { 439 if (rank > Math.min(m.getColumnDimension(), m.getRowDimension())) { 440 return m; 441 } 442 443 final no.uib.cipr.matrix.DenseMatrix mjtA = new no.uib.cipr.matrix.DenseMatrix( 444 m.getArray()); 445 no.uib.cipr.matrix.SVD svd; 446 try { 447 svd = no.uib.cipr.matrix.SVD.factorize(mjtA); 448 } catch (final NotConvergedException e) { 449 throw new RuntimeException(e); 450 } 451 452 final DenseMatrix U = svd.getU(); 453 final DenseMatrix Vt = svd.getVt(); 454 final double[] svector = svd.getS(); 455 final DenseMatrix S = new DenseMatrix(U.numColumns(), Vt.numRows()); 456 for (int i = 0; i < rank; i++) 457 S.set(i, i, svector[i]); 458 459 final DenseMatrix C = new DenseMatrix(U.numRows(), S.numColumns()); 460 final DenseMatrix out = new DenseMatrix(C.numRows(), Vt.numColumns()); 461 U.mult(S, C); 462 C.mult(Vt, out); 463 464 final Matrix outFinal = convert(out); 465 return outFinal; 466 } 467 468 /** 469 * Convert a {@link DenseMatrix} to a {@link Matrix}. 470 * 471 * @param mjt 472 * {@link DenseMatrix} to convert 473 * @return converted matrix. 474 */ 475 public static Matrix convert(DenseMatrix mjt) { 476 return convert(mjt, mjt.numRows(), mjt.numColumns()); 477 } 478 479 /** 480 * Convert a {@link DenseMatrix} to a {@link Matrix}. 481 * 482 * @param mjt 483 * {@link DenseMatrix} to convert 484 * @param nrows 485 * number of rows to copy 486 * @param ncols 487 * number of columns to copy 488 * @return converted matrix. 489 */ 490 public static Matrix convert(DenseMatrix mjt, int nrows, int ncols) { 491 final double[][] d = new double[nrows][ncols]; 492 493 final double[] mjtd = mjt.getData(); 494 for (int r = 0; r < nrows; r++) { 495 for (int c = 0; c < ncols; c++) { 496 d[r][c] = mjtd[r + c * d.length]; 497 } 498 } 499 return new Matrix(d); 500 } 501 502 /** 503 * Create a copy of a matrix with the columns in reverse order. 504 * 505 * @param m 506 * the input matrix 507 * @return a copy with the column order reversed 508 */ 509 public static Matrix reverseColumns(Matrix m) { 510 return reverseColumnsInplace(m.copy()); 511 } 512 513 /** 514 * Reverse the column order of the input matrix inplace. 515 * 516 * @param m 517 * the input matrix 518 * @return the input matrix 519 */ 520 public static Matrix reverseColumnsInplace(Matrix m) { 521 final double[][] data = m.getArray(); 522 final int rows = data.length; 523 final int cols = data[0].length; 524 final int halfCols = cols / 2; 525 526 for (int r = 0; r < rows; r++) { 527 for (int c = 0; c < halfCols; c++) { 528 final double tmp = data[r][c]; 529 data[r][c] = data[r][cols - c - 1]; 530 data[r][cols - c - 1] = tmp; 531 } 532 } 533 534 return m; 535 } 536 537 /** 538 * Create a copy of a matrix with the rows in reverse order. 539 * 540 * @param m 541 * the input matrix 542 * @return a copy with the row order reversed 543 */ 544 public static Matrix reverseRows(Matrix m) { 545 return reverseRowsInplace(m.copy()); 546 } 547 548 /** 549 * Reverse the row order of the input matrix inplace. 550 * 551 * @param m 552 * the input matrix 553 * @return the input matrix 554 */ 555 public static Matrix reverseRowsInplace(Matrix m) { 556 final double[][] data = m.getArray(); 557 final int rows = data.length; 558 final int halfRows = rows / 2; 559 560 for (int r = 0; r < halfRows; r++) { 561 final double[] tmp = data[r]; 562 data[r] = data[rows - r - 1]; 563 data[rows - r - 1] = tmp; 564 } 565 566 return m; 567 } 568 569 /** 570 * Create a diagonal matrix 571 * 572 * @param s 573 * length diagonal numbers 574 * @return new Matrix(s.length,s.length) s.t. diagonal element i,i = s[i] 575 */ 576 public static Matrix diag(double[] s) { 577 final Matrix r = new Matrix(s.length, s.length); 578 for (int i = 0; i < s.length; i++) { 579 r.set(i, i, s[i]); 580 } 581 return r; 582 } 583 584 /** 585 * Set the values of the elements in a single column to a constant value. 586 * 587 * @param m 588 * the matrix 589 * @param c 590 * the column 591 * @param v 592 * the constant value 593 * @return the matrix 594 */ 595 public static Matrix setColumn(Matrix m, int c, double v) { 596 final double[][] data = m.getArray(); 597 final int rows = m.getRowDimension(); 598 599 for (int r = 0; r < rows; r++) 600 data[r][c] = v; 601 602 return m; 603 } 604 605 /** 606 * Set the values of the elements in a single column to a constant value. 607 * 608 * @param m 609 * the matrix 610 * @param r 611 * the row 612 * @param v 613 * the constant value 614 * @return the matrix 615 */ 616 public static Matrix setRow(Matrix m, int r, double v) { 617 final double[][] data = m.getArray(); 618 final int cols = m.getColumnDimension(); 619 620 for (int c = 0; c < cols; c++) 621 data[r][c] = v; 622 623 return m; 624 } 625 626 /** 627 * Fill a matrix with a constant value. 628 * 629 * @param m 630 * the matrix 631 * @param v 632 * the constant value 633 * @return the matrix 634 */ 635 public static Matrix fill(Matrix m, double v) { 636 final double[][] data = m.getArray(); 637 638 final int rows = m.getRowDimension(); 639 final int cols = m.getColumnDimension(); 640 641 for (int r = 0; r < rows; r++) 642 for (int c = 0; c < cols; c++) 643 data[r][c] = v; 644 645 return m; 646 } 647 648 /** 649 * Subtract a constant from all values 650 * 651 * @param m 652 * the matrix 653 * @param v 654 * the constant value 655 * @return the matrix 656 */ 657 public static Matrix minus(Matrix m, double v) { 658 final double[][] data = m.getArray(); 659 660 final int rows = m.getRowDimension(); 661 final int cols = m.getColumnDimension(); 662 663 for (int r = 0; r < rows; r++) 664 for (int c = 0; c < cols; c++) 665 data[r][c] -= v; 666 667 return m; 668 } 669 670 /** 671 * Add a constant to all values 672 * 673 * @param m 674 * the matrix 675 * @param v 676 * the constant value 677 * @return the matrix 678 */ 679 public static Matrix plus(Matrix m, double v) { 680 final double[][] data = m.getArray(); 681 682 final int rows = m.getRowDimension(); 683 final int cols = m.getColumnDimension(); 684 685 for (int r = 0; r < rows; r++) 686 for (int c = 0; c < cols; c++) 687 data[r][c] += v; 688 689 return m; 690 } 691 692 /** 693 * Get a reshaped copy of the input matrix 694 * 695 * @param m 696 * the matrix to reshape 697 * @param newRows 698 * the new number of rows 699 * @return new matrix 700 */ 701 public static Matrix reshape(Matrix m, int newRows) { 702 final int oldCols = m.getColumnDimension(); 703 final int length = oldCols * m.getRowDimension(); 704 final int newCols = length / newRows; 705 final Matrix mat = new Matrix(newRows, newCols); 706 707 final double[][] m1v = m.getArray(); 708 final double[][] m2v = mat.getArray(); 709 710 int r1 = 0, r2 = 0, c1 = 0, c2 = 0; 711 for (int i = 0; i < length; i++) { 712 m2v[r2][c2] = m1v[r1][c1]; 713 714 c1++; 715 if (c1 >= oldCols) { 716 c1 = 0; 717 r1++; 718 } 719 720 c2++; 721 if (c2 >= newCols) { 722 c2 = 0; 723 r2++; 724 } 725 } 726 727 return mat; 728 } 729 730 /** 731 * Get a reshaped copy of the input matrix 732 * 733 * @param m 734 * the matrix to reshape 735 * @param newRows 736 * the new number of rows 737 * @param columnMajor 738 * if true, values are drawn and placed down columns first. if 739 * false values are drawn and placed across rows first 740 * @return new matrix 741 */ 742 public static Matrix reshape(Matrix m, int newRows, boolean columnMajor) { 743 final int oldCols = m.getColumnDimension(); 744 final int oldRows = m.getRowDimension(); 745 final int length = oldCols * m.getRowDimension(); 746 final int newCols = length / newRows; 747 final Matrix mat = new Matrix(newRows, newCols); 748 749 final double[][] m1v = m.getArray(); 750 final double[][] m2v = mat.getArray(); 751 752 int r1 = 0, r2 = 0, c1 = 0, c2 = 0; 753 if (!columnMajor) { 754 for (int i = 0; i < length; i++) { 755 m2v[r2][c2] = m1v[r1][c1]; 756 757 c1++; 758 if (c1 >= oldCols) { 759 c1 = 0; 760 r1++; 761 } 762 763 c2++; 764 if (c2 >= newCols) { 765 c2 = 0; 766 r2++; 767 } 768 } 769 } 770 else { 771 for (int i = 0; i < length; i++) { 772 m2v[r2][c2] = m1v[r1][c1]; 773 774 r1++; 775 if (r1 >= oldRows) { 776 r1 = 0; 777 c1++; 778 } 779 780 r2++; 781 if (r2 >= newRows) { 782 r2 = 0; 783 c2++; 784 } 785 } 786 } 787 788 return mat; 789 } 790 791 /** 792 * Compute the sum of values in a single column 793 * 794 * @param m 795 * the matrix 796 * @param col 797 * the column 798 * @return the sum of values in column col 799 */ 800 public static double sumColumn(Matrix m, int col) { 801 final double[][] data = m.getArray(); 802 final int rows = m.getRowDimension(); 803 804 double sum = 0; 805 for (int r = 0; r < rows; r++) 806 sum += data[r][col]; 807 808 return sum; 809 } 810 811 /** 812 * Compute the sum of values in a single row 813 * 814 * @param m 815 * the matrix 816 * @param row 817 * the row 818 * @return the sum of values in row row 819 */ 820 public static double sumRow(Matrix m, int row) { 821 final double[][] data = m.getArray(); 822 final int cols = m.getColumnDimension(); 823 824 double sum = 0; 825 for (int c = 0; c < cols; c++) 826 sum += data[row][c]; 827 828 return sum; 829 } 830 831 /** 832 * Increment values in a single column by a constant 833 * 834 * @param m 835 * the matrix 836 * @param col 837 * the column 838 * @param value 839 * the constant 840 * @return the matrix 841 */ 842 public static Matrix incrColumn(Matrix m, int col, double value) { 843 final double[][] data = m.getArray(); 844 final int rows = m.getRowDimension(); 845 846 for (int r = 0; r < rows; r++) 847 data[r][col] += value; 848 849 return m; 850 } 851 852 /** 853 * Increment values in a single column by a constant 854 * 855 * @param m 856 * the matrix 857 * @param row 858 * the row 859 * @param value 860 * the constant 861 * @return the sum of values in row row 862 */ 863 public static Matrix incrRow(Matrix m, int row, double value) { 864 final double[][] data = m.getArray(); 865 final int cols = m.getColumnDimension(); 866 867 for (int c = 0; c < cols; c++) 868 data[row][c] += value; 869 870 return m; 871 } 872 873 /** 874 * round (using {@link Math#round(double)} each value of the matrix 875 * 876 * @param times 877 * @return same matrix as handed in 878 */ 879 public static Matrix round(Matrix times) { 880 final double[][] data = times.getArray(); 881 for (int i = 0; i < data.length; i++) { 882 for (int j = 0; j < data[i].length; j++) { 883 data[i][j] = Math.round(data[i][j]); 884 } 885 } 886 return times; 887 } 888 889 /** 890 * min(A,B) returns an array the same size as A and B with the smallest 891 * elements taken from A or B. The dimensions of A and B must match 892 * 893 * @param A 894 * @param B 895 * @return new Matrix filled with min from A and B 896 */ 897 public static Matrix min(Matrix A, Matrix B) { 898 final double[][] dataA = A.getArray(); 899 final double[][] dataB = B.getArray(); 900 final Matrix ret = A.copy(); 901 final double[][] dataRet = ret.getArray(); 902 for (int i = 0; i < dataA.length; i++) { 903 for (int j = 0; j < dataB[i].length; j++) { 904 dataRet[i][j] = Math.min(dataA[i][j], dataB[i][j]); 905 } 906 } 907 return ret; 908 } 909 910 /** 911 * d to the power of each value in range. as with {@link #range} range is: - 912 * a single number (a) (0:1:a) - two numbers (a,b) (a:1:b) - three numbers 913 * (a,b,c) (a:b:c) 914 * 915 * any other amount of range results in a {@link RuntimeException} 916 * 917 * @param d 918 * @param range 919 * @return d to the power of each value in range 920 */ 921 public static Matrix rangePow(double d, double... range) { 922 double start, end, delta; 923 if (range.length == 1) { 924 start = 0; 925 end = range[0]; 926 delta = 1; 927 } else if (range.length == 2) { 928 start = range[0]; 929 end = range[1]; 930 delta = 1; 931 } 932 else if (range.length == 3) { 933 start = range[0]; 934 end = range[2]; 935 delta = range[1]; 936 } 937 else { 938 throw new RuntimeException("Invalid range options selected"); 939 } 940 final int l = (int) ((end - start + 1) / delta); 941 final double[][] out = new double[1][l]; 942 for (int i = 0; i < l; i++) { 943 out[0][i] = Math.pow(d, start + (i * delta)); 944 } 945 return new Matrix(out); 946 } 947 948 /** 949 * range is: - a single number (a) (0:1:a) - two numbers (a,b) (a:1:b) - 950 * three numbers (a,b,c) (a:b:c) 951 * 952 * @param range 953 * @return the range defined 954 */ 955 public static Matrix range(double... range) { 956 double start, end, delta; 957 if (range.length == 1) { 958 start = 0; 959 end = range[0]; 960 delta = 1; 961 } else if (range.length == 2) { 962 start = range[0]; 963 end = range[1]; 964 delta = 1; 965 } 966 else if (range.length == 3) { 967 start = range[0]; 968 end = range[2]; 969 delta = range[1]; 970 } 971 else { 972 throw new RuntimeException("Invalid range options selected"); 973 } 974 final int l = (int) Math.floor((end - start) / delta) + 1; 975 final double[][] out = new double[1][l]; 976 for (int i = 0; i < l; i++) { 977 out[0][i] = start + (i * delta); 978 } 979 return new Matrix(out); 980 } 981 982 /** 983 * range is: - a single number (a) (0:1:a) - two numbers (a,b) (a:1:b) - 984 * three numbers (a,b,c) (a:b:c) 985 * 986 * @param range 987 * @return the range defined 988 */ 989 public static Matrix range(int... range) { 990 int start, end, delta; 991 if (range.length == 1) { 992 start = 0; 993 end = range[0]; 994 delta = 1; 995 } else if (range.length == 2) { 996 start = range[0]; 997 end = range[1]; 998 delta = 1; 999 } 1000 else if (range.length == 3) { 1001 start = range[0]; 1002 end = range[2]; 1003 delta = range[1]; 1004 } 1005 else { 1006 throw new RuntimeException("Invalid range options selected"); 1007 } 1008 final int l = (int) Math.floor((end - start) / delta) + 1; 1009 final double[][] out = new double[1][l]; 1010 for (int i = 0; i < l; i++) { 1011 out[0][i] = start + (i * delta); 1012 } 1013 return new Matrix(out); 1014 } 1015 1016 /** 1017 * Given two row vectors, construct the power set of rowvector combinations 1018 * 1019 * @param A 1020 * @param B 1021 * @return a new matrix of size A.cols * B.cols 1022 */ 1023 public static Matrix ntuples(Matrix A, Matrix B) { 1024 final double[][] Adata = A.getArray(); 1025 final double[][] Bdata = B.getArray(); 1026 1027 final double[][] out = new double[2][Adata[0].length * Bdata[0].length]; 1028 int i = 0; 1029 for (final double a : Adata[0]) { 1030 for (final double b : Bdata[0]) { 1031 out[0][i] = a; 1032 out[1][i] = b; 1033 i++; 1034 } 1035 } 1036 return new Matrix(out); 1037 } 1038 1039 /** 1040 * Given a matrix, repeat the matrix over i rows and j columns 1041 * 1042 * @param x 1043 * @param i 1044 * @param j 1045 * @return repeated matrix 1046 */ 1047 public static Matrix repmat(Matrix x, int i, int j) { 1048 final double[][] xdata = x.getArray(); 1049 final double[][] newmat = new double[xdata.length * i][xdata[0].length * j]; 1050 for (int k = 0; k < newmat.length; k += xdata.length) { 1051 for (int l = 0; l < newmat[0].length; l += xdata[0].length) { 1052 int rowcopyindex = 0; 1053 for (final double[] ds : xdata) { 1054 System.arraycopy(ds, 0, newmat[k + rowcopyindex], l, xdata[0].length); 1055 rowcopyindex += 1; 1056 } 1057 } 1058 } 1059 return new Matrix(newmat); 1060 } 1061 1062 /** 1063 * horizontally stack all the matrices provided. i.e. ret = [x1 x2 x3 x4 ... 1064 * xn] 1065 * 1066 * @param x 1067 * @return horizontally stacked 1068 */ 1069 public static Matrix hstack(Matrix... x) { 1070 final int height = x[0].getRowDimension(); 1071 int width = 0; 1072 for (final Matrix matrix : x) { 1073 width += matrix.getColumnDimension(); 1074 } 1075 final double[][] newmat = new double[height][width]; 1076 int colindex = 0; 1077 for (final Matrix matrix : x) { 1078 final double[][] matdata = matrix.getArray(); 1079 final int w = matrix.getColumnDimension(); 1080 for (int i = 0; i < height; i++) { 1081 System.arraycopy(matdata[i], 0, newmat[i], colindex, w); 1082 } 1083 colindex += w; 1084 } 1085 return new Matrix(newmat); 1086 } 1087 1088 /** 1089 * Add the rows to the mat at rowIndex. Assumes MANY things with no checks: 1090 * rows.rows == rowIndex.length mat.cols == rows.cols rowIndex.length < 1091 * mat.rows for x in rowIndex: x < mat.rows && x >= 0 etc. 1092 * 1093 * @param mat 1094 * @param rows 1095 * @param rowIndex 1096 * @return the input matrix 1097 */ 1098 public static Matrix plusEqualsRow(Matrix mat, Matrix rows, int[] rowIndex) { 1099 final double[][] matdata = mat.getArray(); 1100 final double[][] rowdata = rows.getArray(); 1101 int i = 0; 1102 for (final int row : rowIndex) { 1103 for (int j = 0; j < rowdata[i].length; j++) { 1104 matdata[row][j] += rowdata[i][j]; 1105 } 1106 i++; 1107 } 1108 return mat; 1109 } 1110 1111 /** 1112 * @param x 1113 * @param val 1114 * @return a new matrix for x < val 1115 */ 1116 public static Matrix lessThan(Matrix x, double val) { 1117 final Matrix retMat = x.copy(); 1118 final double[][] data = x.getArray(); 1119 final double[][] retdata = retMat.getArray(); 1120 for (int i = 0; i < data.length; i++) { 1121 for (int j = 0; j < data[i].length; j++) { 1122 retdata[i][j] = data[i][j] < val ? 1 : 0; 1123 } 1124 } 1125 return retMat; 1126 } 1127 1128 /** 1129 * @param x 1130 * @param val 1131 * @return a new matrix for x > val 1132 */ 1133 public static Matrix greaterThan(Matrix x, double val) { 1134 final Matrix retMat = x.copy(); 1135 final double[][] data = x.getArray(); 1136 final double[][] retdata = retMat.getArray(); 1137 for (int i = 0; i < data.length; i++) { 1138 for (int j = 0; j < data[i].length; j++) { 1139 retdata[i][j] = data[i][j] > val ? 1 : 0; 1140 } 1141 } 1142 return retMat; 1143 } 1144 1145 /** 1146 * @param x 1147 * @return a new matrix for x1 && x2 && ... && xn where && means "!=0" 1148 */ 1149 public static Matrix and(Matrix... x) { 1150 final Matrix retMat = MatrixUtils.ones(x[0].getRowDimension(), x[0].getColumnDimension()); 1151 final double[][] retdata = retMat.getArray(); 1152 1153 for (final Matrix matrix : x) { 1154 final double[][] data = matrix.getArray(); 1155 for (int i = 0; i < data.length; i++) { 1156 for (int j = 0; j < data[i].length; j++) { 1157 retdata[i][j] = (retdata[i][j] != 0 && data[i][j] != 0) ? 1 : 0; 1158 } 1159 } 1160 } 1161 return retMat; 1162 } 1163 1164 /** 1165 * @param rowDimension 1166 * @param columnDimension 1167 * @return matrix of dimensions filled with ones 1168 */ 1169 public static Matrix ones(int rowDimension, int columnDimension) { 1170 final Matrix ret = new Matrix(rowDimension, columnDimension); 1171 return plus(ret, 1); 1172 } 1173 1174 /** 1175 * @param x 1176 * @return logical-and each column of x 1177 */ 1178 public static Matrix all(Matrix x) { 1179 final int cols = x.getColumnDimension(); 1180 final int rows = x.getRowDimension(); 1181 final Matrix ret = new Matrix(1, cols); 1182 final double[][] retdata = ret.getArray(); 1183 final double[][] data = x.getArray(); 1184 for (int i = 0; i < cols; i++) { 1185 boolean cool = true; 1186 for (int j = 0; j < rows; j++) { 1187 cool = data[j][i] != 0 && cool; 1188 if (!cool) 1189 break; 1190 } 1191 retdata[0][i] = cool ? 1 : 0; 1192 } 1193 return ret; 1194 } 1195 1196 /** 1197 * @param vals 1198 * @return given vals, return the array indexes where vals != 0 1199 */ 1200 public static int[] valsToIndex(double[] vals) { 1201 int nindex = 0; 1202 for (final double d : vals) { 1203 nindex += d != 0 ? 1 : 0; 1204 } 1205 1206 final int[] indexes = new int[nindex]; 1207 nindex = 0; 1208 int i = 0; 1209 for (final double d : vals) { 1210 if (d != 0) { 1211 indexes[i] = nindex; 1212 i++; 1213 } 1214 nindex++; 1215 } 1216 return indexes; 1217 } 1218 1219 /** 1220 * for every value in x greater than val set toset 1221 * 1222 * @param x 1223 * @param val 1224 * @param toset 1225 * @return same matrix handed in 1226 */ 1227 public static Matrix greaterThanSet(Matrix x, int val, int toset) { 1228 final double[][] data = x.getArray(); 1229 for (int i = 0; i < data.length; i++) { 1230 for (int j = 0; j < data[i].length; j++) { 1231 data[i][j] = data[i][j] > val ? toset : data[i][j]; 1232 } 1233 } 1234 return x; 1235 } 1236 1237 /** 1238 * for every value in x less than val set toset 1239 * 1240 * @param x 1241 * @param val 1242 * @param toset 1243 * @return same matrix handed in 1244 */ 1245 public static Matrix lessThanSet(Matrix x, int val, int toset) { 1246 final double[][] data = x.getArray(); 1247 for (int i = 0; i < data.length; i++) { 1248 for (int j = 0; j < data[i].length; j++) { 1249 data[i][j] = data[i][j] < val ? toset : data[i][j]; 1250 } 1251 } 1252 return x; 1253 } 1254 1255 /** 1256 * Subtract the given row vector from every row of the given matrix, 1257 * returning the result in a new matrix. 1258 * 1259 * @param in 1260 * the matrix 1261 * @param row 1262 * the row vector 1263 * @return the resultant matrix 1264 */ 1265 public static Matrix minusRow(Matrix in, double[] row) { 1266 final Matrix out = in.copy(); 1267 final double[][] outData = out.getArray(); 1268 final int rows = out.getRowDimension(); 1269 final int cols = out.getColumnDimension(); 1270 1271 for (int r = 0; r < rows; r++) { 1272 for (int c = 0; c < cols; c++) { 1273 outData[r][c] -= row[c]; 1274 } 1275 } 1276 1277 return out; 1278 } 1279 1280 /** 1281 * Subtract the given col vector (held as a Matrix) from every col of the 1282 * given matrix, returning the result in a new matrix. 1283 * 1284 * @param in 1285 * the matrix 1286 * @param col 1287 * the col Matrix (Only the first column is used) 1288 * @return the resultant matrix 1289 */ 1290 public static Matrix minusCol(Matrix in, Matrix col) { 1291 final Matrix out = in.copy(); 1292 final double[][] outData = out.getArray(); 1293 final int rows = out.getRowDimension(); 1294 final int cols = out.getColumnDimension(); 1295 final double[][] colArr = col.getArray(); 1296 1297 for (int r = 0; r < rows; r++) { 1298 for (int c = 0; c < cols; c++) { 1299 outData[r][c] -= colArr[r][0]; 1300 } 1301 } 1302 1303 return out; 1304 } 1305 1306 /** 1307 * Add a matrix to another inline. 1308 * 1309 * @param result 1310 * the matrix to add to 1311 * @param add 1312 * the matrix to add 1313 * @return the result matrix 1314 */ 1315 public static Matrix plusEquals(Matrix result, Matrix add) { 1316 final int rows = result.getRowDimension(); 1317 final int cols = result.getColumnDimension(); 1318 1319 final double[][] resultData = result.getArray(); 1320 final double[][] addData = add.getArray(); 1321 1322 for (int r = 0; r < rows; r++) { 1323 for (int c = 0; c < cols; c++) { 1324 resultData[r][c] += addData[r][c]; 1325 } 1326 } 1327 1328 return result; 1329 } 1330 1331 /** 1332 * Multiply a matrix by a constant inplace, returning the matrix. 1333 * 1334 * @param m 1335 * the matrix 1336 * @param val 1337 * the value to multiply by 1338 * @return the matrix 1339 */ 1340 public static Matrix times(Matrix m, double val) { 1341 final double[][] data = m.getArray(); 1342 1343 final int rows = m.getRowDimension(); 1344 final int cols = m.getColumnDimension(); 1345 1346 for (int r = 0; r < rows; r++) 1347 for (int c = 0; c < cols; c++) 1348 data[r][c] *= val; 1349 1350 return m; 1351 } 1352 1353 /** 1354 * Convert an mtj matrix into a 2d double array 1355 * 1356 * @param mat 1357 * @return a double array 1358 */ 1359 public static double[][] mtjToDoubleArray(no.uib.cipr.matrix.DenseMatrix mat) { 1360 final double[][] out = new double[mat.numRows()][mat.numColumns()]; 1361 final double[] data = mat.getData(); 1362 for (int r = 0; r < out.length; r++) { 1363 final double[] outr = out[r]; 1364 for (int c = 0; c < out[0].length; c++) { 1365 outr[c] = data[r + c * out.length]; 1366 } 1367 } 1368 return out; 1369 } 1370 1371 /** 1372 * Compute the sum of values in all rows 1373 * 1374 * @param m 1375 * the matrix 1376 * @return the sum of values across all cols in all rows 1377 */ 1378 public static Matrix sumRows(Matrix m) { 1379 final double[][] data = m.getArray(); 1380 final int cols = m.getColumnDimension(); 1381 final int rows = m.getRowDimension(); 1382 1383 final Matrix sum = new Matrix(rows, 1); 1384 final double[][] sumArr = sum.getArray(); 1385 for (int c = 0; c < cols; c++) { 1386 for (int r = 0; r < rows; r++) 1387 { 1388 sumArr[r][0] += data[r][c]; 1389 } 1390 } 1391 1392 return sum; 1393 } 1394 1395 /** 1396 * Compute the sum of values in all cols 1397 * 1398 * @param m 1399 * the matrix 1400 * @return the sum of values across all rows in all cols 1401 */ 1402 public static Matrix sumCols(Matrix m) { 1403 final double[][] data = m.getArray(); 1404 final int cols = m.getColumnDimension(); 1405 final int rows = m.getRowDimension(); 1406 1407 final Matrix sum = new Matrix(1, cols); 1408 final double[][] sumArr = sum.getArray(); 1409 for (int c = 0; c < cols; c++) { 1410 for (int r = 0; r < rows; r++) 1411 { 1412 sumArr[0][c] += data[r][c]; 1413 } 1414 } 1415 1416 return sum; 1417 } 1418 1419 /** 1420 * Generate a matrix with Gaussian distributed randoms 1421 * 1422 * @param rows 1423 * the number of rows 1424 * @param cols 1425 * the number of columns 1426 * @return a matrix containing values drawn from a 0 mean 1.0 sdev gaussian 1427 */ 1428 public static Matrix randGaussian(int rows, int cols) { 1429 final Matrix m = new Matrix(rows, cols); 1430 final double[][] d = m.getArray(); 1431 final Random r = new Random(); 1432 for (int row = 0; row < d.length; row++) { 1433 for (int col = 0; col < d[row].length; col++) { 1434 d[row][col] = r.nextGaussian(); 1435 } 1436 } 1437 return m; 1438 } 1439 1440 /** 1441 * Compute the sparsity (i.e. ratio of non-zero elements to matrix size) of 1442 * the given matrix 1443 * 1444 * @param matrix 1445 * the matrix 1446 * @return the sparsity 1447 */ 1448 public static double sparcity(SparseMatrix matrix) { 1449 final double density = matrix.used() / ((double) matrix.rowCount() * (double) matrix.columnCount()); 1450 return 1 - density; 1451 } 1452 1453 /** 1454 * Extract the diagonal component from the given matrix 1455 * 1456 * @param cv 1457 * the matrix 1458 * @return a new matrix with the diagonal values from the input matrix and 1459 * other values set to zero. 1460 */ 1461 public static Matrix diag(Matrix cv) { 1462 final Matrix d = new Matrix(cv.getRowDimension(), cv.getColumnDimension()); 1463 1464 for (int i = 0; i < Math.min(cv.getRowDimension(), cv.getColumnDimension()); i++) 1465 d.set(i, i, cv.get(i, i)); 1466 1467 return d; 1468 } 1469 1470 /** 1471 * Extract the diagonal component from the given matrix 1472 * 1473 * @param cv 1474 * the matrix 1475 * @return a new matrix with the diagonal values from the input matrix and 1476 * other values set to zero. 1477 */ 1478 public static double[] diagVector(Matrix cv) { 1479 final double[] d = new double[Math.min(cv.getRowDimension(), cv.getColumnDimension())]; 1480 1481 for (int i = 0; i < Math.min(cv.getRowDimension(), cv.getColumnDimension()); i++) 1482 d[i] = cv.get(i, i); 1483 1484 return d; 1485 } 1486 1487 /** 1488 * Format a matrix as a single-line string suitable for using in matlab or 1489 * octave 1490 * 1491 * @param mat 1492 * the matrix to format 1493 * @return the string 1494 */ 1495 public static String toMatlabString(Matrix mat) { 1496 return "[" + toString(mat).trim().replace("\n ", ";").replace(" ", ",") + "]"; 1497 } 1498 1499 /** 1500 * Format a matrix as a single-line string suitable for using in python 1501 * 1502 * @param mat 1503 * the matrix to format 1504 * @return the string 1505 */ 1506 public static String toPythonString(Matrix mat) { 1507 return "[[" + toString(mat).trim().replace("\n ", "][").replace(" ", ",") + "]]"; 1508 } 1509 1510 /** 1511 * @param mat 1512 * @return trace of the matrix 1513 */ 1514 public static double trace(Matrix mat) { 1515 double sum = 0; 1516 for (int i = 0; i < mat.getRowDimension(); i++) { 1517 sum += mat.get(i, i); 1518 } 1519 return sum; 1520 } 1521 1522 /** 1523 * Solves the system <code>Ax = 0</code>, returning the vector x as an 1524 * array. Internally computes the least-squares solution using the SVD of 1525 * <code>A</code>. 1526 * 1527 * @param A 1528 * the matrix describing the system 1529 * @return the solution vector 1530 */ 1531 public static double[] solveHomogeneousSystem(Matrix A) { 1532 return solveHomogeneousSystem(new DenseMatrix(A.getArray())); 1533 } 1534 1535 /** 1536 * Solves the system <code>Ax = 0</code>, returning the vector x as an 1537 * array. Internally computes the least-squares solution using the SVD of 1538 * <code>A</code>. 1539 * 1540 * @param A 1541 * the matrix describing the system 1542 * @return the solution vector 1543 */ 1544 public static double[] solveHomogeneousSystem(double[][] A) { 1545 return solveHomogeneousSystem(new DenseMatrix(A)); 1546 } 1547 1548 /** 1549 * Solves the system <code>Ax = 0</code>, returning the vector x as an 1550 * array. Internally computes the least-squares solution using the SVD of 1551 * <code>A</code>. 1552 * 1553 * @param A 1554 * the matrix describing the system 1555 * @return the solution vector 1556 */ 1557 public static double[] solveHomogeneousSystem(DenseMatrix A) { 1558 try { 1559 final SVD svd = SVD.factorize(A); 1560 1561 final double[] x = new double[svd.getVt().numRows()]; 1562 final int c = svd.getVt().numColumns() - 1; 1563 1564 for (int i = 0; i < x.length; i++) { 1565 x[i] = svd.getVt().get(c, i); 1566 } 1567 1568 return x; 1569 } catch (final NotConvergedException e) { 1570 throw new RuntimeException(e); 1571 } 1572 } 1573 1574 /** 1575 * Format a matrix as a single-line string suitable for using in java 1576 * 1577 * @param mat 1578 * the matrix to format 1579 * @return the string 1580 */ 1581 public static String toJavaString(Matrix mat) { 1582 return "{" + toString(mat).trim().replaceAll("^", "{").replace("\n ", "},{").replace(" ", ",") + "}}"; 1583 } 1584 1585 /** 1586 * Construct a matrix from a row-packed (i.e. row-by-row) vector of the 1587 * data. 1588 * 1589 * @param vector 1590 * the row-packed vector 1591 * @param ncols 1592 * the number of columns 1593 * @return the reconstructed matrix 1594 */ 1595 public static Matrix fromRowPacked(double[] vector, int ncols) { 1596 final int nrows = vector.length / ncols; 1597 1598 final Matrix a = new Matrix(nrows, ncols); 1599 final double[][] ad = a.getArray(); 1600 for (int r = 0, i = 0; r < nrows; r++) 1601 for (int c = 0; c < ncols; c++, i++) 1602 ad[r][c] = vector[i]; 1603 1604 return a; 1605 } 1606 1607 /** 1608 * Compute the covariance matrix of the given samples (assumed each sample 1609 * is a row). 1610 * 1611 * @param m 1612 * the samples matrix 1613 * @return the covariance matrix 1614 */ 1615 public static Matrix covariance(Matrix m) { 1616 final int N = m.getRowDimension(); 1617 return times(m.transpose().times(m), 1.0 / (N > 1 ? N - 1 : N)); 1618 } 1619 1620 /** 1621 * For each element of X, sign(X) returns 1 if the element is greater than 1622 * zero, 0 if it equals zero and -1 if it is less than zero. 1623 * 1624 * @param m 1625 * the matrix 1626 * @return the sign matrix 1627 */ 1628 public static Matrix sign(Matrix m) { 1629 final Matrix o = new Matrix(m.getRowDimension(), m.getColumnDimension()); 1630 final double[][] md = m.getArray(); 1631 final double[][] od = o.getArray(); 1632 1633 for (int r = 0; r < o.getRowDimension(); r++) { 1634 for (int c = 0; c < o.getColumnDimension(); c++) { 1635 if (md[r][c] > 0) 1636 od[r][c] = 1; 1637 if (md[r][c] < 0) 1638 od[r][c] = -1; 1639 } 1640 } 1641 1642 return o; 1643 } 1644 1645 /** 1646 * Return a copy of the input matrix where every value is the exponential of 1647 * the elements, e to the X. 1648 * 1649 * @param m 1650 * the input matrix 1651 * @return the exponential matrix 1652 */ 1653 public static Matrix exp(Matrix m) { 1654 final Matrix o = new Matrix(m.getRowDimension(), m.getColumnDimension()); 1655 final double[][] md = m.getArray(); 1656 final double[][] od = o.getArray(); 1657 1658 for (int r = 0; r < o.getRowDimension(); r++) { 1659 for (int c = 0; c < o.getColumnDimension(); c++) { 1660 od[r][c] = Math.exp(md[r][c]); 1661 } 1662 } 1663 1664 return o; 1665 } 1666 1667 /** 1668 * Return a copy of the input matrix where every value is the hyerbolic 1669 * tangent of the elements. 1670 * 1671 * @param m 1672 * the input matrix 1673 * @return the tanh matrix 1674 */ 1675 public static Matrix tanh(Matrix m) { 1676 final Matrix o = new Matrix(m.getRowDimension(), m.getColumnDimension()); 1677 final double[][] md = m.getArray(); 1678 final double[][] od = o.getArray(); 1679 1680 for (int r = 0; r < o.getRowDimension(); r++) { 1681 for (int c = 0; c < o.getColumnDimension(); c++) { 1682 od[r][c] = Math.tanh(md[r][c]); 1683 } 1684 } 1685 1686 return o; 1687 } 1688}