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}