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 gov.sandia.cognition.math.matrix.DimensionalityMismatchException;
033import gov.sandia.cognition.math.matrix.Matrix;
034import gov.sandia.cognition.math.matrix.MatrixEntry;
035import gov.sandia.cognition.math.matrix.MatrixFactory;
036import gov.sandia.cognition.math.matrix.Vector;
037import gov.sandia.cognition.math.matrix.VectorEntry;
038import gov.sandia.cognition.math.matrix.mtj.DenseMatrixFactoryMTJ;
039import gov.sandia.cognition.math.matrix.mtj.SparseColumnMatrix;
040import gov.sandia.cognition.math.matrix.mtj.SparseMatrixFactoryMTJ;
041import gov.sandia.cognition.math.matrix.mtj.SparseRowMatrix;
042import gov.sandia.cognition.math.matrix.mtj.SparseVector;
043
044import java.util.Random;
045
046import no.uib.cipr.matrix.sparse.FlexCompColMatrix;
047import no.uib.cipr.matrix.sparse.FlexCompRowMatrix;
048
049import com.jmatio.types.MLArray;
050import com.jmatio.types.MLDouble;
051
052/**
053 * Utility methods for dealing with the cognitive foundry {@link Matrix}.
054 * 
055 * @author Sina Samangooei (ss@ecs.soton.ac.uk)
056 * 
057 */
058public class CFMatrixUtils {
059        private static final double EPS = 1e-100;
060
061        /**
062         * Create a new matrix with the absolute values of the input matrix.
063         * 
064         * @param mat
065         *            input matrix
066         * @return absolute matrix
067         */
068        public static Matrix abs(Matrix mat) {
069                final Matrix ret = mat.clone();
070                final int nrows = ret.getNumRows();
071                final int ncols = ret.getNumColumns();
072                for (int r = 0; r < nrows; r++) {
073                        for (int c = 0; c < ncols; c++) {
074                                ret.setElement(r, c, Math.abs(mat.getElement(r, c)));
075                        }
076                }
077                return ret;
078        }
079
080        /**
081         * Compute the absolute sum of values in the matrix
082         * 
083         * @param mat
084         *            the matrix
085         * @return the absolute sum
086         */
087        public static double absSum(Matrix mat) {
088                if (mat instanceof SparseColumnMatrix) {
089                        return absSumSparse((SparseColumnMatrix) mat);
090                } else if (mat instanceof SparseRowMatrix) {
091                        return absSumSparse((SparseRowMatrix) mat);
092                }
093
094                double tot = 0;
095                final int nrows = mat.getNumRows();
096                final int ncols = mat.getNumColumns();
097                for (int r = 0; r < nrows; r++) {
098                        for (int c = 0; c < ncols; c++) {
099                                final double element = mat.getElement(r, c);
100                                if (Double.isNaN(element)) {
101                                        throw new RuntimeException("hmm?");
102                                }
103                                tot += Math.abs(element);
104                        }
105                }
106                return tot;
107        }
108
109        /**
110         * @param mat
111         * @return sum of a {@link SparseColumnMatrix}
112         */
113        public static double absSumSparse(SparseColumnMatrix mat) {
114                double sum = 0;
115                for (int i = 0; i < mat.getNumColumns(); i++) {
116                        sum += mat.getColumn(i).sum();
117                }
118                return sum;
119        }
120
121        /**
122         * @param mat
123         * @return sum of a {@link SparseRowMatrix}
124         */
125        public static double absSumSparse(SparseRowMatrix mat) {
126                double sum = 0;
127                for (int i = 0; i < mat.getNumRows(); i++) {
128                        sum += mat.getRow(i).sum();
129                }
130                return sum;
131        }
132
133        /**
134         * Multiply a matrix by a constant, storing the results in the input matrix.
135         * 
136         * @param mat
137         *            the matrix
138         * @param etat
139         *            the constant
140         * @return the input matrix
141         */
142        public static Matrix timesInplace(Matrix mat, double etat) {
143                mat.scaleEquals(etat);
144                return mat;
145        }
146
147        /**
148         * Convert a matlab {@link MLArray} to a {@link Matrix}
149         * 
150         * @param mlArray
151         *            the matrlab matrix
152         * @return the matrix
153         */
154        public static Matrix asMat(MLArray mlArray) {
155                final MLDouble mlArrayDbl = (MLDouble) mlArray;
156                final int rows = mlArray.getM();
157                final int cols = mlArray.getN();
158
159                final Matrix mat = SparseMatrixFactoryMTJ.INSTANCE.createMatrix(rows, cols);
160
161                for (int r = 0; r < rows; r++) {
162                        for (int c = 0; c < cols; c++) {
163                                mat.setElement(r, c, mlArrayDbl.get(r, c));
164                        }
165                }
166                return mat;
167        }
168
169        /**
170         * Convert a matlab {@link MLArray} to a {@link Matrix}
171         * 
172         * @param name
173         * @param mat
174         * 
175         * @return the matrix
176         */
177        public static MLArray toMLArray(String name, Matrix mat) {
178                final MLDouble mlArrayDbl = new MLDouble(name, new int[] { mat.getNumRows(), mat.getNumColumns() });
179
180                for (final MatrixEntry matrixEntry : mat) {
181                        mlArrayDbl.set(matrixEntry.getValue(), matrixEntry.getRowIndex(), matrixEntry.getColumnIndex());
182                }
183                return mlArrayDbl;
184        }
185
186        /**
187         * Compute the proportion of completely zero rows to rows with non-zero
188         * values
189         * 
190         * @param mat
191         *            the matrix
192         * @return the row sparsity
193         */
194        public static double rowSparsity(Matrix mat) {
195                final double nrows = mat.getNumRows();
196                double nsparse = 0;
197                for (int r = 0; r < nrows; r++) {
198                        if (mat.getRow(r).sum() == 0) {
199                                nsparse++;
200                        }
201                }
202                return nsparse / nrows;
203        }
204
205        /**
206         * Compute the proportion of completely zero columns to columns with
207         * non-zero values
208         * 
209         * @param mat
210         *            the matrix
211         * @return the column sparsity
212         */
213        public static double colSparcity(Matrix mat) {
214                final double ncols = mat.getNumColumns();
215                double nsparse = 0;
216                for (int c = 0; c < ncols; c++) {
217                        if (mat.getColumn(c).sum() == 0) {
218                                nsparse++;
219                        }
220                }
221                return nsparse / ncols;
222        }
223
224        /**
225         * Add a constant to the matrix, returning the input matrix
226         * 
227         * @param mat
228         *            the matrix
229         * @param etat
230         *            the constant
231         * @return the matrix
232         */
233        public static Matrix plusInplace(Matrix mat, double etat) {
234                final int nrows = mat.getNumRows();
235                final int ncols = mat.getNumColumns();
236                for (int r = 0; r < nrows; r++) {
237                        for (int c = 0; c < ncols; c++) {
238                                mat.setElement(r, c, mat.getElement(r, c) + etat);
239                        }
240                }
241                return mat;
242        }
243
244        /**
245         * Extract the diagonal elements as a vector
246         * 
247         * @param mat
248         *            the matrix to extract from
249         * @return the diagonal
250         */
251        public static Vector diag(Matrix mat) {
252                Vector ret;
253
254                if (mat.getNumColumns() > mat.getNumRows()) {
255                        ret = mat.getRow(0);
256                }
257                else {
258                        ret = mat.getColumn(0);
259                }
260                final int rowcol = ret.getDimensionality();
261                for (int rc = 0; rc < rowcol; rc++) {
262                        ret.setElement(rc, mat.getElement(rc, rc));
263                }
264                return ret;
265        }
266
267        /**
268         * Stack matrices vertically
269         * 
270         * @param matrixFactory
271         *            factory to create output matrix
272         * @param matricies
273         *            matrices to stack
274         * @return matrix created from the stacking
275         */
276        public static Matrix vstack(MatrixFactory<? extends Matrix> matrixFactory, Matrix... matricies) {
277                int nrows = 0;
278                int ncols = 0;
279                for (final Matrix matrix : matricies) {
280                        nrows += matrix.getNumRows();
281                        ncols = matrix.getNumColumns();
282                }
283                final Matrix ret = matrixFactory.createMatrix(nrows, ncols);
284                int currentRow = 0;
285                for (final Matrix matrix : matricies) {
286                        ret.setSubMatrix(currentRow, 0, matrix);
287                        currentRow += matrix.getNumRows();
288                }
289                return ret;
290        }
291
292        /**
293         * Stack matrices vertically
294         * 
295         * @param matricies
296         *            matrices to stack
297         * @return matrix created from the stacking
298         */
299        public static Matrix vstack(Matrix... matricies) {
300                return vstack(MatrixFactory.getDefault(), matricies);
301        }
302
303        /**
304         * Get the data array backing this matrix (in column-major format)
305         * 
306         * @param w
307         *            the matrix
308         * @return the data
309         */
310        public static double[] getData(Matrix w) {
311                return ((no.uib.cipr.matrix.DenseMatrix) DenseMatrixFactoryMTJ.INSTANCE.copyMatrix(w).getInternalMatrix())
312                                .getData();
313        }
314
315        /**
316         * Get the minimum element value
317         * 
318         * @param u
319         *            the matrix
320         * @return the min value
321         */
322        public static double min(Matrix u) {
323                double min = Double.MAX_VALUE;
324                for (final MatrixEntry matrixEntry : u) {
325                        min = Math.min(min, matrixEntry.getValue());
326                }
327                return min;
328        }
329
330        /**
331         * Get the maximum element value
332         * 
333         * @param u
334         *            the matrix
335         * @return the max value
336         */
337        public static double max(Matrix u) {
338                double max = -Double.MAX_VALUE;
339                for (final MatrixEntry matrixEntry : u) {
340                        max = Math.max(max, matrixEntry.getValue());
341                }
342                return max;
343        }
344
345        /**
346         * Get the minimum element value
347         * 
348         * @param column
349         *            the vector
350         * @return the min value
351         */
352        public static double min(Vector column) {
353                double min = Double.MAX_VALUE;
354                for (final VectorEntry vectorEntry : column) {
355                        min = Math.min(min, vectorEntry.getValue());
356                }
357                return min;
358        }
359
360        /**
361         * Get the maximum element value
362         * 
363         * @param column
364         *            the vector
365         * @return the max value
366         */
367        public static double max(Vector column) {
368                double max = -Double.MAX_VALUE;
369                for (final VectorEntry vectorEntry : column) {
370                        max = Math.max(max, vectorEntry.getValue());
371                }
372                return max;
373        }
374
375        /**
376         * Compute the sparsity
377         * 
378         * @param mat
379         *            the matrix
380         * @return the sparsity
381         */
382        public static double sparsity(Matrix mat) {
383                double count = 0;
384                final double size = mat.getNumRows() * mat.getNumColumns();
385                if (mat instanceof SparseRowMatrix) {
386                        for (int i = 0; i < mat.getNumRows(); i++) {
387                                final SparseVector row = (SparseVector) mat.getRow(i);
388                                count += row.getNumElementsUsed();
389                        }
390                } else if (mat instanceof SparseColumnMatrix) {
391                        for (int i = 0; i < mat.getNumColumns(); i++) {
392                                final SparseVector col = (SparseVector) mat.getColumn(i);
393                                count += col.getNumElementsUsed();
394                        }
395                } else {
396                        for (final MatrixEntry matrixEntry : mat) {
397                                if (matrixEntry.getValue() != 0)
398                                        count++;
399                        }
400                }
401
402                return (size - count) / size;
403        }
404
405        /**
406         * Bring each element to the power d
407         * 
408         * @param degree
409         * @param d
410         * @return the input
411         */
412        public static <T extends Matrix> T powInplace(T degree, double d) {
413                for (final MatrixEntry ent : degree) {
414                        degree.setElement(ent.getRowIndex(), ent.getColumnIndex(), Math.pow(ent.getValue(), d));
415                }
416                return degree;
417        }
418
419        /**
420         * Bring each element to the power d
421         * 
422         * @param degree
423         * @param d
424         * @return the input
425         */
426        public static <T extends Vector> T powInplace(T degree, double d) {
427                for (final VectorEntry ent : degree) {
428                        degree.setElement(ent.getIndex(), Math.pow(ent.getValue(), d));
429                }
430                return degree;
431        }
432
433        /**
434         * @param laplacian
435         * @return copy and convert
436         */
437        public static Jama.Matrix asJama(Matrix laplacian) {
438
439                final Jama.Matrix ret = new Jama.Matrix(laplacian.getNumRows(), laplacian.getNumColumns());
440                for (final MatrixEntry matrixEntry : laplacian) {
441                        ret.set(matrixEntry.getRowIndex(), matrixEntry.getColumnIndex(), matrixEntry.getValue());
442                }
443
444                return ret;
445        }
446
447        /**
448         * @param vt
449         * @return mean of each row
450         */
451        public static Vector rowMean(Matrix vt) {
452                final Vector sumOfColumns = vt.sumOfColumns();
453                sumOfColumns.scaleEquals(1. / vt.getNumColumns());
454                return sumOfColumns;
455        }
456
457        /**
458         * @param vt
459         * @return mean of each row
460         */
461        public static Vector colMean(Matrix vt) {
462                final Vector sumOfColumns = vt.sumOfRows();
463                sumOfColumns.scaleEquals(1. / vt.getNumRows());
464                return sumOfColumns;
465        }
466
467        /**
468         * @param A
469         * @param col
470         */
471        public static void minusEqualsCol(Matrix A, Vector col) {
472                for (int i = 0; i < A.getNumRows(); i++) {
473                        for (int j = 0; j < A.getNumColumns(); j++) {
474                                A.setElement(i, j, A.getElement(i, j) - col.getElement(i));
475                        }
476                }
477        }
478
479        /**
480         * @param A
481         * @param row
482         */
483        public static void minusEqualsRow(Matrix A, Vector row) {
484                for (int i = 0; i < A.getNumRows(); i++) {
485                        for (int j = 0; j < A.getNumColumns(); j++) {
486                                A.setElement(i, j, A.getElement(i, j) - row.getElement(j));
487                        }
488                }
489        }
490
491        /**
492         * Create a random {@link SparseColumnMatrix}
493         * 
494         * @param rows
495         *            number of rows
496         * @param cols
497         *            number of columns
498         * @param min
499         *            the minimum value
500         * @param max
501         *            the maximum value
502         * @param density
503         *            the matrix density
504         * @param random
505         *            the RNG
506         * @return the random matrix
507         */
508        public static SparseColumnMatrix randomSparseCol(int rows, int cols, double min, double max, double density,
509                        Random random)
510        {
511                final SparseColumnMatrix ret = SparseMatrixFactoryMTJ.INSTANCE.createWrapper(new FlexCompColMatrix(rows, cols));
512                for (int i = 0; i < cols; i++) {
513                        final Vector v = ret.getColumn(i);
514                        for (int j = 0; j < rows; j++) {
515                                if (random.nextDouble() <= density) {
516                                        v.setElement(j, random.nextDouble() * (max - min) + min);
517                                }
518                        }
519                }
520                return ret;
521        }
522
523        /**
524         * Create a random {@link SparseRowMatrix}
525         * 
526         * @param rows
527         *            number of rows
528         * @param cols
529         *            number of columns
530         * @param min
531         *            the minimum value
532         * @param max
533         *            the maximum value
534         * @param density
535         *            the matrix density
536         * @param random
537         *            the RNG
538         * @return the random matrix
539         */
540        public static SparseRowMatrix randomSparseRow(int rows, int cols, double min, double max, double density,
541                        Random random)
542        {
543                final SparseRowMatrix ret = SparseMatrixFactoryMTJ.INSTANCE.createWrapper(new FlexCompRowMatrix(rows, cols));
544                for (int i = 0; i < rows; i++) {
545                        final Vector v = ret.getRow(i);
546                        for (int j = 0; j < cols; j++) {
547                                if (random.nextDouble() <= density) {
548                                        v.setElement(j, random.nextDouble() * (max - min) + min);
549                                }
550                        }
551                }
552                return ret;
553        }
554
555        /**
556         * @param a
557         * @param b
558         * @return performs a dot product taking advantage of the sparcity in b and
559         *         a
560         */
561        public static SparseRowMatrix fastsparsedot(SparseRowMatrix a, SparseColumnMatrix b) {
562                final SparseRowMatrix ret = SparseMatrixFactoryMTJ.INSTANCE.createMatrix(a.getNumRows(), b.getNumColumns());
563                if (a.getNumColumns() != b.getNumRows()) {
564                        return null;
565                }
566                for (int i = 0; i < a.getNumRows(); i++) {
567                        final no.uib.cipr.matrix.sparse.SparseVector arow = a.getInternalMatrix().getRow(i);
568                        for (int j = 0; j < b.getNumColumns(); j++) {
569                                double v = 0;
570                                final no.uib.cipr.matrix.sparse.SparseVector bcol = b.getInternalMatrix().getColumn(j);
571                                final no.uib.cipr.matrix.sparse.SparseVector leading;
572                                final no.uib.cipr.matrix.sparse.SparseVector other;
573                                if (arow.getUsed() < bcol.getUsed()) {
574                                        leading = arow;
575                                        other = bcol;
576                                } else {
577                                        leading = bcol;
578                                        other = arow;
579                                }
580                                for (final no.uib.cipr.matrix.VectorEntry vectorEntry : leading) {
581                                        v += vectorEntry.get() * other.get(vectorEntry.index());
582                                }
583                                if (Math.abs(v) > EPS) {
584                                        ret.setElement(i, j, v);
585                                }
586                        }
587                }
588
589                return ret;
590        }
591
592        /**
593         * @param a
594         * @param b
595         * @return checks for the fastest way to do this dot product
596         */
597        public static Matrix fastdot(Matrix a, Matrix b) {
598                if (a instanceof SparseRowMatrix && b instanceof SparseColumnMatrix) {
599                        return fastsparsedot((SparseRowMatrix) a, (SparseColumnMatrix) b);
600                }
601                return a.times(b);
602        }
603
604        /**
605         * @param a
606         * @return turns the provided matrix into a {@link SparseColumnMatrix}
607         */
608        public static SparseColumnMatrix asSparseColumn(Matrix a) {
609                return SparseMatrixFactoryMTJ.INSTANCE.createWrapper(
610                                new FlexCompColMatrix(
611                                                SparseMatrixFactoryMTJ.INSTANCE.copyMatrix(a).getInternalMatrix()
612                                )
613                                );
614        }
615
616        /**
617         * Convert a {@link Matrix} to a {@link SparseRowMatrix}
618         * 
619         * @param a
620         * @return the {@link SparseRowMatrix}
621         */
622        public static SparseRowMatrix asSparseRow(Matrix a) {
623                return SparseMatrixFactoryMTJ.INSTANCE.copyMatrix(a);
624        }
625
626        /**
627         * 
628         * @param ret
629         * @param c
630         * @param col
631         */
632        public static void fastsetcol(Matrix ret, int c, Vector col) {
633                if (ret instanceof SparseColumnMatrix && col instanceof SparseVector) {
634                        ((SparseColumnMatrix) ret).setColumn(c, (SparseVector) col);
635                }
636                else {
637                        ret.setColumn(c, col);
638                }
639        }
640
641        /**
642         * @param A
643         * @param B
644         * @return A - B, done using
645         *         {@link #fastsparseminusEquals(SparseColumnMatrix, SparseColumnMatrix)}
646         *         if possible
647         */
648        public static Matrix fastminusEquals(Matrix A, Matrix B) {
649                if (A instanceof SparseColumnMatrix && B instanceof SparseColumnMatrix) {
650                        return fastsparseminusEquals((SparseColumnMatrix) A, (SparseColumnMatrix) B);
651                }
652                A.minusEquals(B);
653                return A;
654        }
655
656        /**
657         * @param A
658         * @param B
659         * @return A - B, done using {@link #fastminusEquals(Matrix, Matrix)} if
660         *         possible
661         */
662        public static Matrix fastminus(Matrix A, Matrix B) {
663                return fastminusEquals(A.clone(), B);
664        }
665
666        /**
667         * @param A
668         * @param B
669         * @return A - B
670         */
671        public static Matrix fastsparseminusEquals(SparseColumnMatrix A, SparseColumnMatrix B) {
672                if (A.getNumColumns() != B.getNumColumns() || A.getNumRows() != B.getNumRows()) {
673                        throw new DimensionalityMismatchException();
674                }
675                final SparseColumnMatrix ret = A;
676
677                final FlexCompColMatrix retint = ret.getInternalMatrix();
678                final FlexCompColMatrix Bint = B.getInternalMatrix();
679                for (int i = 0; i < A.getNumColumns(); i++) {
680                        final no.uib.cipr.matrix.sparse.SparseVector aCol = retint.getColumn(i);
681                        final no.uib.cipr.matrix.sparse.SparseVector bCol = Bint.getColumn(i);
682                        aCol.add(-1, bCol);
683                }
684                return ret;
685        }
686
687        /**
688         * @param A
689         * @param B
690         * @return A - B
691         */
692        public static Matrix fastsparseminusEquals(SparseRowMatrix A, SparseRowMatrix B) {
693                if (A.getNumColumns() != B.getNumColumns() || A.getNumRows() != B.getNumRows()) {
694                        throw new DimensionalityMismatchException();
695                }
696                final SparseRowMatrix ret = A;
697
698                final FlexCompRowMatrix retInt = ret.getInternalMatrix();
699                final FlexCompRowMatrix bint = B.getInternalMatrix();
700                for (int i = 0; i < A.getNumRows(); i++) {
701                        final no.uib.cipr.matrix.sparse.SparseVector aCol = retInt.getRow(i);
702                        final no.uib.cipr.matrix.sparse.SparseVector bCol = bint.getRow(i);
703                        aCol.add(-1, bCol);
704                }
705                return ret;
706        }
707
708        /**
709         * @param mat
710         * @return checks elements using {@link Double#isNaN()}
711         */
712        public static boolean containsNaN(Matrix mat) {
713                for (final MatrixEntry matrixEntry : mat) {
714                        if (Double.isNaN(matrixEntry.getValue())) {
715                                return true;
716                        }
717                }
718                return false;
719        }
720
721        /**
722         * @param vec
723         * @return checks elements using {@link Double#isNaN()}
724         */
725        public static boolean containsNaN(Vector vec) {
726                for (final VectorEntry vectorEntry : vec) {
727                        if (Double.isNaN(vectorEntry.getValue())) {
728                                return true;
729                        }
730                }
731                return false;
732        }
733
734        /**
735         * @param mat
736         * @return checks elements using {@link Double#isInfinite()}
737         */
738        public static boolean containsInfinity(Matrix mat) {
739                for (final MatrixEntry matrixEntry : mat) {
740                        if (Double.isInfinite(matrixEntry.getValue())) {
741                                return true;
742                        }
743                }
744                return false;
745        }
746
747        /**
748         * Sum the matrix entries
749         * 
750         * @param A
751         * @return the sum
752         */
753        public static double sum(Matrix A) {
754                double sum = 0;
755                for (final MatrixEntry matrixEntry : A) {
756                        sum += matrixEntry.getValue();
757                }
758                return sum;
759        }
760
761}