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}