001/******************************************************************************* 002 * This software is provided as a supplement to the authors' textbooks on digital 003 * image processing published by Springer-Verlag in various languages and editions. 004 * Permission to use and distribute this software is granted under the BSD 2-Clause 005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit http://imagingbook.com for additional details. 008 *******************************************************************************/ 009 010package imagingbook.lib.math; 011 012import imagingbook.lib.settings.PrintPrecision; 013 014import java.io.ByteArrayOutputStream; 015import java.io.PrintStream; 016import java.util.ArrayList; 017import java.util.List; 018import java.util.Locale; 019 020import org.apache.commons.math3.linear.DecompositionSolver; 021import org.apache.commons.math3.linear.LUDecomposition; 022import org.apache.commons.math3.linear.MatrixUtils; 023import org.apache.commons.math3.linear.RealMatrix; 024import org.apache.commons.math3.linear.RealVector; 025import org.apache.commons.math3.linear.SingularMatrixException; 026 027/** 028 * This class contains a collection of static methods for calculations 029 * with vectors and matrices using native Java arrays without any enclosing 030 * objects structures. 031 * Matrices are simply two-dimensional array M[r][c], where r is the row index 032 * and c is the column index (as common in linear algebra). This means that 033 * matrices are really vectors of row vectors. 034 * TODO: need to differentiate functional and side-effect methods! 035 * TODO: add JavaDoc comments. 036 * 037 * @author WB 038 * @version 2016/11/28 039 */ 040 041public abstract class Matrix { 042 043// static { 044// Locale.setDefault(Locale.US); 045// } 046 047 static Locale loc = Locale.US; 048 049 // Vector and matrix creation 050 051 public static double[] createDoubleVector(int length) { 052 return new double[length]; 053 } 054 055 public static float[] createFloatVector(int length) { 056 return new float[length]; 057 } 058 059 public static double[][] createDoubleMatrix(int rows, int columns) { 060 return new double[rows][columns]; 061 } 062 063 public static float[][] createFloatMatrix(int rows, int columns) { 064 return new float[rows][columns]; 065 } 066 067 // Specific vector/matrix creation: 068 069 public static double[] zeroVector(int size) { 070 return new double[size]; 071 } 072 073 public static double[][] idMatrix(int size) { 074 double[][] A = new double[size][size]; 075 for (int i = 0; i < size; i++) { 076 A[i][i] = 1; 077 } 078 return A; 079 } 080 081 // Matrix properties ------------------------------------- 082 083 public static int getNumberOfRows(double[][] A) { 084 return A.length; 085 } 086 087 public static int getNumberOfColumns(double[][] A) { 088 return A[0].length; 089 } 090 091 public static int getNumberOfRows(float[][] A) { 092 return A.length; 093 } 094 095 public static int getNumberOfColumns(float[][] A) { 096 return A[0].length; 097 } 098 099 // Extract rows or columns 100 101 public static double[] getRow(double[][] A, int r) { 102 return A[r].clone(); 103 } 104 105 public static double[] getColumn(double[][] A, int c) { 106 final int rows = A.length; 107 double[] col = new double[rows]; 108 for (int r = 0; r < rows; r++) { 109 col[r] = A[r][c]; 110 } 111 return col; 112 } 113 114 // Matrix and vector duplication ------------------------------ 115 116 public static double[] duplicate(final double[] A) { 117 return A.clone(); 118 } 119 120 public static float[] duplicate(final float[] A) { 121 return A.clone(); 122 } 123 124 public static double[][] duplicate(final double[][] A) { 125 final int m = A.length; 126 final double[][] B = new double[m][]; 127 for (int i = 0; i < m; i++) { 128 B[i] = A[i].clone(); 129 } 130 return B; 131 } 132 133 public static float[][] duplicateToFloat(final double[][] A) { 134 final int m = A.length; 135 final int n = A[0].length; 136 final float[][] B = new float[m][n]; 137 for (int i = 0; i < m; i++) { 138 for (int j = 0; j < n; j++) { 139 B[i][j] = (float) A[i][j]; 140 } 141 } 142 return B; 143 } 144 145 public static float[][] duplicate(final float[][] A) { 146 final int m = A.length; 147 float[][] B = new float[m][]; 148 for (int i = 0; i < m; i++) { 149 B[i] = A[i].clone(); 150 } 151 return B; 152 } 153 154 public static double[][] duplicateToDouble(final float[][] A) { 155 final int m = A.length; 156 final int n = A[0].length; 157 final double[][] B = new double[m][n]; 158 for (int i = 0; i < m; i++) { 159 for (int j = 0; j < n; j++) { 160 B[i][j] = A[i][j]; 161 } 162 } 163 return B; 164 } 165 166 // Element-wise arithmetic ------------------------------- 167 168 //TODO: change to multiple args: public static int[] add(int[]... as) 169 170 public static int[] add(int[] a, int[] b) { 171 int[] c = new int[a.length]; 172 for (int i = 0; i < a.length; i++) { 173 c[i] = c[i] + b[i]; 174 } 175 return c; 176 } 177 178 public static double[] add(double[] a, double[] b) { 179 double[] c = new double[a.length]; 180 for (int i = 0; i < a.length; i++) { 181 c[i] = a[i] + b[i]; 182 } 183 return c; 184 } 185 186 public static double[][] add(double[][] A, double[][] B) { 187 final int m = A.length; 188 final int n = A[0].length; 189 double[][] C = new double[m][n]; 190 for (int i = 0; i < m; i++) { 191 for (int j = 0; j < n; j++) { 192 C[i][j] = A[i][j] + B[i][j]; 193 } 194 } 195 return C; 196 } 197 198 public static double[] subtract(double[] a, double[] b) { 199 double[] c = a.clone(); 200 for (int i = 0; i < a.length; i++) { 201 c[i] = c[i] - b[i]; 202 } 203 return c; 204 } 205 206 public static double[] subtract(double[] a, int[] b) { 207 double[] c = a.clone(); 208 for (int i = 0; i < a.length; i++) { 209 c[i] = c[i] - b[i]; 210 } 211 return c; 212 } 213 214 public static int[] floor(double[] a) { 215 int[] b = new int[a.length]; 216 for (int i = 0; i < a.length; i++) { 217 b[i] = (int) Math.floor(a[i]); 218 } 219 return b; 220 } 221 222 // Scalar multiplications ------------------------------- 223 224 // non-destructive 225 public static double[] multiply(final double s, final double[] a) { 226 double[] b = a.clone(); 227 multiplyD(s, b); 228 return b; 229 } 230 231 // destructive 232 public static void multiplyD(final double s, final double[] a) { 233 for (int i = 0; i < a.length; i++) { 234 a[i] = a[i] * s; 235 } 236 } 237 238 239 // non-destructive 240 public static double[][] multiply(final double s, final double[][] A) { 241 double[][] B = duplicate(A); 242 multiplyD(s, B); 243 return B; 244 } 245 246 public static void multiplyD(final double s, final double[][] A) { 247 for (int i = 0; i < A.length; i++) { 248 for (int j = 0; j < A[i].length; j++) { 249 A[i][j] = A[i][j] * s; 250 } 251 } 252 } 253 254 // non-destructive 255 public static float[] multiply(final float s, final float[] A) { 256 float[] B = duplicate(A); 257 multiplyD(s, B); 258 return B; 259 } 260 261 // destructive 262 public static void multiplyD(final float s, final float[] A) { 263 for (int i = 0; i < A.length; i++) { 264 A[i] = A[i] * s; 265 } 266 } 267 268 // non-destructive 269 public static float[][] multiply(final float s, final float[][] A) { 270 float[][] B = duplicate(A); 271 for (int i = 0; i < B.length; i++) { 272 for (int j = 0; j < B[i].length; j++) { 273 B[i][j] = B[i][j] * s; 274 } 275 } 276 return B; 277 } 278 279 // destructive 280 public static void multiplyD(final float s, final float[][] A) { 281 for (int i = 0; i < A.length; i++) { 282 for (int j = 0; j < A[i].length; j++) { 283 A[i][j] = A[i][j] * s; 284 } 285 } 286 } 287 288 // matrix-vector multiplications ---------------------------------------- 289 290 // non-destructive 291 public static double[] multiply(final double[] x, final double[][] A) { 292 double[] Y = new double[getNumberOfColumns(A)]; 293 multiplyD(x, A, Y); 294 return Y; 295 } 296 297 /* 298 * Implements a right (post-) matrix-vector multiplication: x . A -> y 299 * x is treated as a row vector of length m, matrix A is of size (m,n). 300 * y (a row vector of length n) is modified. 301 * destructive 302 */ 303 public static void multiplyD(final double[] x, final double[][] A, double[] y) { 304 final int m = getNumberOfRows(A); 305 final int n = getNumberOfColumns(A); 306 if (x.length != m || y.length != n) 307 throw new IllegalArgumentException("incompatible vector-matrix dimensions"); 308 for (int i = 0; i < n; i++) { 309 double s = 0; 310 for (int j = 0; j < m; j++) { 311 s = s + x[j] * A[j][i]; 312 } 313 y[i] = s; 314 } 315 } 316 317 318 /* 319 * implements a left (pre-) matrix-vector multiplication: A . x -> y 320 * Matrix A is of size (m,n), column vector x is of length n. 321 * The result y is a column vector of length m. 322 * non-destructive 323 */ 324 public static double[] multiply(final double[][] A, final double[] x) { 325 double[] y = new double[getNumberOfRows(A)]; 326 multiplyD(A, x, y); 327 return y; 328 } 329 330 // destructive 331 public static void multiplyD(final double[][] A, final double[] x, double[] y) { 332 final int m = getNumberOfRows(A); 333 final int n = getNumberOfColumns(A); 334 if (x.length != n || y.length != m) 335 throw new IllegalArgumentException("incompatible matrix-vector dimensions"); 336 for (int i = 0; i < m; i++) { 337 double s = 0; 338 for (int j = 0; j < n; j++) { 339 s = s + A[i][j] * x[j]; 340 } 341 y[i] = s; 342 } 343 } 344 345 // non-destructive 346 public static float[] multiply(final float[][] A, final float[] x) { 347 float[] y = new float[getNumberOfRows(A)]; 348 multiplyD(A, x, y); 349 return y; 350 } 351 352 /** 353 * Matrix-vector product: A . x = y 354 * All arguments must be appropriately sized. destructive 355 * @param A matrix of size m,n (input) 356 * @param x vector of length n (input) 357 * @param y vector of length m (result) 358 */ 359 public static void multiplyD(final float[][] A, final float[] x, float[] y) { 360 final int m = getNumberOfRows(A); 361 final int n = getNumberOfColumns(A); 362 if (x.length != n || y.length != m) 363 throw new IllegalArgumentException("incompatible matrix-vector dimensions"); 364 for (int i = 0; i < m; i++) { 365 double s = 0; 366 for (int j = 0; j < n; j++) { 367 s = s + A[i][j] * x[j]; 368 } 369 y[i] = (float) s; 370 } 371 } 372 373 374 375 // Matrix-matrix products --------------------------------------- 376 377 // returns A * B (non-destructive) 378 public static double[][] multiply(final double[][] A, final double[][] B) { 379 int m = getNumberOfRows(A); 380 int q = getNumberOfColumns(B); 381 double[][] C = createDoubleMatrix(m, q); 382 multiplyD(A, B, C); 383 return C; 384 } 385 386 // A * B -> C (destructive) 387 public static void multiplyD(final double[][] A, final double[][] B, final double[][] C) { 388 final int mA = getNumberOfRows(A); 389 final int nA = getNumberOfColumns(A); 390 final int nB = getNumberOfColumns(B); 391 for (int i = 0; i < mA; i++) { 392 for (int j = 0; j < nB; j++) { 393 double s = 0; 394 for (int k = 0; k < nA; k++) { 395 s = s + A[i][k] * B[k][j]; 396 } 397 C[i][j] = s; 398 } 399 } 400 } 401 402 // returns A * B (non-destructive) 403 public static float[][] multiply(final float[][] A, final float[][] B) { 404 // TODO: also check nA = mB 405 final int mA = getNumberOfRows(A); 406 final int nB = getNumberOfColumns(B); 407 float[][] C = createFloatMatrix(mA, nB); 408 multiply(A, B, C); 409 return C; 410 } 411 412 // A * B -> C (destructive) 413 public static void multiply(final float[][] A, final float[][] B, final float[][] C) { 414 final int mA = getNumberOfRows(A); 415 final int nA = getNumberOfColumns(A); 416 final int mB = getNumberOfRows(B); 417 final int nB = getNumberOfColumns(B); 418 if (nA != mB) 419 throw new IllegalArgumentException("Matrix.multiply: wrong row/col dimensions"); 420 for (int i = 0; i < mA; i++) { 421 for (int j = 0; j < nB; j++) { 422 float s = 0; 423 for (int k = 0; k < nA; k++) { 424 s = s + A[i][k] * B[k][j]; 425 } 426 C[i][j] = s; 427 } 428 } 429 } 430 431 // Vector-vector products --------------------------------------- 432 433 // A is considered a row vector, B is a column vector, both of length n. 434 // returns a scalar vale. 435 public static double dotProduct(final double[] A, final double[] B) { 436 double sum = 0; 437 for (int i = 0; i < A.length; i++) { 438 sum = sum + A[i] * B[i]; 439 } 440 return sum; 441 } 442 443 // A is considered a column vector, B is a row vector, of length m, n, resp. 444 // returns a matrix M of size (m,n). 445 public static double[][] outerProduct(final double[] A, final double[] B) { 446 final int m = A.length; 447 final int n = B.length; 448 final double[][] M = new double[m][n]; 449 for (int i = 0; i < m; i++) { 450 for (int j = 0; j < n; j++) { 451 M[i][j] = A[i] * B[j]; 452 } 453 } 454 return M; 455 } 456 457 // Vector norms --------------------------------------------------- 458 459 public static double normL1(final double[] A) { 460 double sum = 0; 461 for (double x : A) { 462 sum = sum + Math.abs(x); 463 } 464 return sum; 465 } 466 467 public static double normL2(final double[] A) { 468 return Math.sqrt(normL2squared(A)); 469 } 470 471 public static double normL2squared(final double[] A) { 472 double sum = 0; 473 for (double x : A) { 474 sum = sum + (x * x); 475 } 476 return sum; 477 } 478 479 public static float normL1(final float[] A) { 480 double sum = 0; 481 for (double x : A) { 482 sum = sum + Math.abs(x); 483 } 484 return (float) sum; 485 } 486 487 public static float normL2(final float[] A) { 488 return (float) Math.sqrt(normL2squared(A)); 489 } 490 491 public static float normL2squared(final float[] A) { 492 double sum = 0; 493 for (double x : A) { 494 sum = sum + (x * x); 495 } 496 return (float) sum; 497 } 498 499 // Summation -------------------------------------------------- 500 501 public static double sum(final double[] A) { 502 double sum = 0; 503 for (int i = 0; i < A.length; i++) { 504 sum = sum + A[i]; 505 } 506 return sum; 507 } 508 509 public static double sum(final double[][] A) { 510 double sum = 0; 511 for (int i = 0; i < A.length; i++) { 512 for (int j = 0; j < A[i].length; j++) { 513 sum = sum + A[i][j]; 514 } 515 } 516 return sum; 517 } 518 519 public static float sum(final float[] A) { 520 double sum = 0; 521 for (int i = 0; i < A.length; i++) { 522 sum = sum + A[i]; 523 } 524 return (float) sum; 525 } 526 527 public static double sum(final float[][] A) { 528 double sum = 0; 529 for (int i = 0; i < A.length; i++) { 530 for (int j = 0; j < A[i].length; j++) { 531 sum = sum + A[i][j]; 532 } 533 } 534 return sum; 535 } 536 537 // Min/max of vectors ------------------------ 538 539 public static float min(final float[] A) { 540 float minval = Float.POSITIVE_INFINITY; 541 for (float val : A) { 542 if (val < minval) { 543 minval = val; 544 } 545 } 546 return minval; 547 } 548 549 550 public static double min(final double[] A) { 551 double minval = Double.POSITIVE_INFINITY; 552 for (double val : A) { 553 if (val < minval) { 554 minval = val; 555 } 556 } 557 return minval; 558 } 559 560 public static float max(final float[] A) { 561 float maxval = Float.NEGATIVE_INFINITY; 562 for (float val : A) { 563 if (val > maxval) { 564 maxval = val; 565 } 566 } 567 return maxval; 568 } 569 570 571 public static double max(final double[] A) { 572 double maxval = Double.NEGATIVE_INFINITY; 573 for (double val : A) { 574 if (val > maxval) { 575 maxval = val; 576 } 577 } 578 return maxval; 579 } 580 581 // Vector concatenation ----------------------- 582 583 public static float[] concatenate(float[]... xs) { 584 List<Float> vlist = new ArrayList<Float>(); 585 for (float[] a : xs) { 586 for (float val : a) { 587 vlist.add(val); 588 } 589 } 590 591 float[] va = new float[vlist.size()]; 592 int i = 0; 593 for (float val : vlist) { 594 va[i] = val; 595 i++; 596 } 597 return va; 598 } 599 600 public static double[] concatenate(double[]... xs) { 601 List<Double> vlist = new ArrayList<Double>(); 602 for (double[] a : xs) { 603 for (double val : a) { 604 vlist.add(val); 605 } 606 } 607 608 double[] va = new double[vlist.size()]; 609 int i = 0; 610 for (double val : vlist) { 611 va[i] = val; 612 i++; 613 } 614 return va; 615 } 616 617 // Determinants -------------------------------------------- 618 619 public static float determinant2x2(final float[][] A) { 620 return A[0][0] * A[1][1] - A[0][1] * A[1][0]; 621 } 622 623 public static double determinant2x2(final double[][] A) { 624 return A[0][0] * A[1][1] - A[0][1] * A[1][0]; 625 } 626 627 public static float determinant3x3(final float[][] A) { 628 return 629 A[0][0] * A[1][1] * A[2][2] + 630 A[0][1] * A[1][2] * A[2][0] + 631 A[0][2] * A[1][0] * A[2][1] - 632 A[2][0] * A[1][1] * A[0][2] - 633 A[2][1] * A[1][2] * A[0][0] - 634 A[2][2] * A[1][0] * A[0][1] ; 635 } 636 637 public static double determinant3x3(final double[][] A) { 638 return 639 A[0][0] * A[1][1] * A[2][2] + 640 A[0][1] * A[1][2] * A[2][0] + 641 A[0][2] * A[1][0] * A[2][1] - 642 A[2][0] * A[1][1] * A[0][2] - 643 A[2][1] * A[1][2] * A[0][0] - 644 A[2][2] * A[1][0] * A[0][1] ; 645 } 646 647 // Matrix transposition --------------------------------------- 648 649 public static float[][] transpose(float[][] A) { 650 final int m = getNumberOfRows(A); 651 final int n = getNumberOfColumns(A); 652 float[][] At = new float[n][m]; 653 for (int i = 0; i < m; i++) { 654 for (int j = 0; j < n; j++) { 655 At[j][i] = A[i][j]; 656 } 657 } 658 return At; 659 } 660 661 public static double[][] transpose(double[][] A) { 662 final int m = getNumberOfRows(A); 663 final int n = getNumberOfColumns(A); 664 double[][] At = new double[n][m]; 665 for (int i = 0; i < m; i++) { 666 for (int j = 0; j < n; j++) { 667 At[j][i] = A[i][j]; 668 } 669 } 670 return At; 671 } 672 673 // Matrix Froebenius norm --------------------------------------- 674 675 public static double froebeniusNorm(final double[][] A) { 676 final int m = getNumberOfRows(A); 677 final int n = getNumberOfColumns(A); 678 double s = 0; 679 for (int i = 0; i < m; i++) { 680 for (int j = 0; j < n; j++) { 681 s = s + A[i][j] * A[i][j]; 682 } 683 } 684 return Math.sqrt(s); 685 } 686 687 // Matrix trace --------------------------------------- 688 689 public static double trace(final double[][] A) { 690 final int m = getNumberOfRows(A); 691 final int n = getNumberOfColumns(A); 692 if (m != n) 693 throw new IllegalArgumentException("square matrix expected"); 694 double s = 0; 695 for (int i = 0; i < m; i++) { 696 s = s + A[i][i]; 697 } 698 return s; 699 } 700 701 702 // Matrix inversion --------------------------------------- 703 704 705 /** 706 * @param A a square matrix. 707 * @return the inverse of A or null if A is non-square or singular. 708 */ 709 public static double[][] inverse(final double[][] A) { 710 RealMatrix M = MatrixUtils.createRealMatrix(A); 711 if (!M.isSquare()) 712 return null; 713 else { 714 double[][] Ai = null; 715 try { 716 RealMatrix Mi = MatrixUtils.inverse(M); //new LUDecomposition(M).getSolver().getInverse(); 717 Ai = Mi.getData(); 718 } catch (SingularMatrixException e) {} 719 return Ai; 720 } 721 } 722 723 public static float[][] inverse(final float[][] A) { 724 double[][] B = duplicateToDouble(A); 725 double[][] Bi = inverse(B); 726 if (Bi == null) 727 return null; 728 else 729 return duplicateToFloat(Bi); 730 } 731 732 // numerically stable? 733 @Deprecated 734 public static float[][] inverse2x2(final float[][] A) { 735 float[][] B = duplicate(A); 736 final double det = determinant2x2(B); 737 if (Math.abs(det) < Arithmetic.EPSILON_DOUBLE) 738 return null; 739 else { 740 final double a00 = B[0][0]; 741 final double a01 = B[0][1]; 742 final double a10 = B[1][0]; 743 final double a11 = B[1][1]; 744 B[0][0] = (float) ( a11 / det); 745 B[0][1] = (float) (-a01 / det); 746 B[1][0] = (float) (-a10 / det); 747 B[1][1] = (float) ( a00 / det); 748 return B; 749 } 750 } 751 752 // numerically stable? 753 @Deprecated 754 public static double[][] inverse2x2(final double[][] A) { 755 double[][] B = duplicate(A); 756 final double det = determinant2x2(B); 757 if (Math.abs(det) < Arithmetic.EPSILON_DOUBLE) 758 return null; 759 else { 760 final double a00 = B[0][0]; 761 final double a01 = B[0][1]; 762 final double a10 = B[1][0]; 763 final double a11 = B[1][1]; 764 B[0][0] = a11 / det; 765 B[0][1] = -a01 / det; 766 B[1][0] = -a10 / det; 767 B[1][1] = a00 / det; 768 return B; 769 } 770 } 771 772 // use general method, i.e. double[][] inverse(double[][] A) 773// @Deprecated 774// public static double[][] inverse3x3(final double[][] A) { 775// double[][] B = duplicate(A); 776// final double det = determinant3x3(B); 777// if (Math.abs(det) < Arithmetic.EPSILON_DOUBLE) 778// return null; 779// else { 780// final double a00 = B[0][0]; 781// final double a01 = B[0][1]; 782// final double a02 = B[0][2]; 783// final double a10 = B[1][0]; 784// final double a11 = B[1][1]; 785// final double a12 = B[1][2]; 786// final double a20 = B[2][0]; 787// final double a21 = B[2][1]; 788// final double a22 = B[2][2]; 789// B[0][0] = (a11 * a22 - a12 * a21) / det; 790// B[0][1] = (a02 * a21 - a01 * a22) / det; 791// B[0][2] = (a01 * a12 - a02 * a11) / det; 792// 793// B[1][0] = (a12 * a20 - a10 * a22) / det; 794// B[1][1] = (a00 * a22 - a02 * a20) / det; 795// B[1][2] = (a02 * a10 - a00 * a12) / det; 796// 797// B[2][0] = (a10 * a21 - a11 * a20) / det; 798// B[2][1] = (a01 * a20 - a00 * a21) / det; 799// B[2][2] = (a00 * a11 - a01 * a10) / det; 800// return B; 801// } 802// } 803 804 // numerically stable? should be replaced by standard inversion 805// @Deprecated 806// public static float[][] inverse3x3(final float[][] A) { 807// final float[][] B = duplicate(A); 808// final double det = determinant3x3(B); 809// // IJ.log(" determinant = " + det); 810// if (Math.abs(det) < Arithmetic.EPSILON_DOUBLE) 811// return null; 812// else { 813// final double a00 = B[0][0]; 814// final double a01 = B[0][1]; 815// final double a02 = B[0][2]; 816// final double a10 = B[1][0]; 817// final double a11 = B[1][1]; 818// final double a12 = B[1][2]; 819// final double a20 = B[2][0]; 820// final double a21 = B[2][1]; 821// final double a22 = B[2][2]; 822// B[0][0] = (float) ((a11 * a22 - a12 * a21) / det); 823// B[0][1] = (float) ((a02 * a21 - a01 * a22) / det); 824// B[0][2] = (float) ((a01 * a12 - a02 * a11) / det); 825// 826// B[1][0] = (float) ((a12 * a20 - a10 * a22) / det); 827// B[1][1] = (float) ((a00 * a22 - a02 * a20) / det); 828// B[1][2] = (float) ((a02 * a10 - a00 * a12) / det); 829// 830// B[2][0] = (float) ((a10 * a21 - a11 * a20) / det); 831// B[2][1] = (float) ((a01 * a20 - a00 * a21) / det); 832// B[2][2] = (float) ((a00 * a11 - a01 * a10) / det); 833// return B; 834// } 835// } 836 837 // ------------------------------------------------------------------------ 838 839 // Finds the EXACT solution x for A.x = b 840 public static double[] solve(final double[][] A, double[] b) { 841 RealMatrix AA = MatrixUtils.createRealMatrix(A); 842 RealVector bb = MatrixUtils.createRealVector(b); 843 DecompositionSolver solver = new LUDecomposition(AA).getSolver(); 844 double[] x = null; 845 try { 846 x = solver.solve(bb).toArray(); 847 } catch (SingularMatrixException e) {} 848 return x; 849 } 850 851 // Output to streams and strings ------------------------------------------ 852 853 public static String toString(double[] x) { 854 ByteArrayOutputStream bas = new ByteArrayOutputStream(); 855 PrintStream strm = new PrintStream(bas); 856 printToStream(x, strm); 857 return bas.toString(); 858 } 859 860 public static void printToStream(double[] A, PrintStream strm) { 861 String fStr = PrintPrecision.getFormatStringFloat(); 862 strm.format("{"); 863 for (int i = 0; i < A.length; i++) { 864 if (i > 0) 865 strm.format(", "); 866 strm.format(loc, fStr, A[i]); 867 } 868 strm.format("}"); 869 strm.flush(); 870 } 871 872 public static String toString(double[][] A) { 873 ByteArrayOutputStream bas = new ByteArrayOutputStream(); 874 PrintStream strm = new PrintStream(bas); 875 printToStream(A, strm); 876 return bas.toString(); 877 } 878 879 public static void printToStream(double[][] A, PrintStream strm) { 880 String fStr = PrintPrecision.getFormatStringFloat(); 881 strm.format("{"); 882 for (int i=0; i< A.length; i++) { 883 if (i == 0) 884 strm.format("{"); 885 else 886 strm.format(", \n{"); 887 for (int j=0; j< A[i].length; j++) { 888 if (j == 0) 889 strm.format(loc, fStr, A[i][j]); 890 else 891 strm.format(loc, ", " + fStr, A[i][j]); 892 } 893 strm.format("}"); 894 } 895 strm.format("}"); 896 strm.flush(); 897 } 898 899 public static String toString(float[] A) { 900 ByteArrayOutputStream bas = new ByteArrayOutputStream(); 901 PrintStream strm = new PrintStream(bas); 902 printToStream(A, strm); 903 return bas.toString(); 904 } 905 906 public static void printToStream(float[] A, PrintStream strm) { 907 String fStr = PrintPrecision.getFormatStringFloat(); 908 strm.format("{"); 909 for (int i = 0; i < A.length; i++) { 910 if (i > 0) 911 strm.format(", "); 912 strm.format(loc, fStr, A[i]); 913 } 914 strm.format("}"); 915 strm.flush(); 916 } 917 918 public static String toString(float[][] A) { 919 ByteArrayOutputStream bas = new ByteArrayOutputStream(); 920 PrintStream strm = new PrintStream(bas); 921 printToStream(A, strm); 922 return bas.toString(); 923 } 924 925 public static void printToStream(float[][] A, PrintStream strm) { 926 String fStr = PrintPrecision.getFormatStringFloat(); 927 strm.format("{"); 928 for (int i=0; i< A.length; i++) { 929 if (i == 0) 930 strm.format("{"); 931 else 932 strm.format(", \n{"); 933 for (int j=0; j< A[i].length; j++) { 934 if (j == 0) 935 strm.format(loc, fStr, A[i][j]); 936 else 937 strm.format(loc, ", " + fStr, A[i][j]); 938 } 939 strm.format("}"); 940 } 941 strm.format("}"); 942 strm.flush(); 943 } 944 945 //-------------------------------------------------------------------------- 946 947 948 public static void main(String[] args) { 949 float[][] A = { 950 { -1, 2, 3 }, 951 { 4, 5, 6 }, 952 { 7, 8, 9 }}; 953 954 System.out.println("A = \n" + toString(A)); 955 System.out.println("A rows = " + getNumberOfRows(A)); 956 System.out.println("A columns = " + getNumberOfColumns(A)); 957 int row = 1; 958 int column = 2; 959 System.out.println("A[1][2] = " + A[row][column]); 960 961 System.out.println("det=" + determinant3x3(A)); 962 float[][] Ai = inverse(A); 963 toString(Ai); 964 965 double[][] B = {{ -1, 2, 3 }, { 4, 5, 6 }}; 966 System.out.println("B = \n" + toString(B)); 967 System.out.println("B rows = " + getNumberOfRows(B)); 968 System.out.println("B columns = " + getNumberOfColumns(B)); 969 970 PrintPrecision.set(5); 971 972 double[][] C = new double[2][3]; 973 System.out.println("C rows = " + getNumberOfRows(C)); 974 System.out.println("C columns = " + getNumberOfColumns(C)); 975 976 RealMatrix Ba = MatrixUtils.createRealMatrix(B); 977 System.out.println("Ba = " + Ba.toString()); 978 979 float[] v1 = {1,2,3}; 980 float[] v2 = {4,5,6,7}; 981 float[] v3 = {8}; 982 float[] v123 = concatenate(v1, v2, v3); 983 System.out.println("v123 = \n" + toString(v123)); 984 985 System.out.println("mind1 = " + Matrix.min(new double[] {-20,30,60,-40, 0})); 986 System.out.println("maxd2 = " + Matrix.max(new double[] {-20,30,60,-40, 0})); 987 System.out.println("minf1 = " + Matrix.min(new float[] {-20,30,60,-40, 0})); 988 System.out.println("maxf2 = " + Matrix.max(new float[] {-20,30,60,-40, 0})); 989 } 990}