コード例 #1
0
        public void TestUpdating()
        {
            // first row
            var m          = DoubleFactory2D.Dense.Make(_a.ViewColumn(0).ToArray(), _a.Rows);
            var initialSVD = new SingularValueDecomposition(m);
            var u          = initialSVD.U;
            var s          = initialSVD.S;
            var v          = initialSVD.V;

            // second row
            var d  = DoubleFactory2D.Dense.Make(_a.ViewColumn(1).ToArray(), _a.Rows);
            var l  = u.ViewDice().ZMult(d, null);
            var uu = u.ZMult(u.ViewDice(), null);
            var ul = uu.ZMult(d, null);
            var h  = d.Copy().Assign(uu.ZMult(d, null), BinaryFunctions.Minus);
            var k  = Math.Sqrt(d.Aggregate(BinaryFunctions.Plus, a => a * a) - (2 * l.Aggregate(BinaryFunctions.Plus, a => a * a)) + ul.Aggregate(BinaryFunctions.Plus, a => a * a));
            var j1 = h.Assign(UnaryFunctions.Div(k));

            Assert.AreEqual(j1.Assign(UnaryFunctions.Mult(k)), h);

            var q =
                DoubleFactory2D.Dense.Compose(
                    new[] { new[] { s, l }, new[] { null, DoubleFactory2D.Dense.Make(1, 1, k) } });
            var svdq = new SingularValueDecomposition(q);
            var u2   = DoubleFactory2D.Dense.AppendColumns(u, j1).ZMult(svdq.U, null);
            var s2   = svdq.S;
            var v2   = DoubleFactory2D.Dense.ComposeDiagonal(v, DoubleFactory2D.Dense.Identity(1)).ZMult(
                svdq.V, null);

            var svd = new SingularValueDecomposition(_a.ViewPart(0, 0, _a.Rows, 2));

            Assert.AreEqual(svd.S, s2);
        }
コード例 #2
0
ファイル: Algebra.cs プロジェクト: cobaltblueocean/Colt.NET
        /// <summary>
        /// Outer product of two vectors; Sets <i>A[i,j] = x[i] * y[j]</i>.
        /// </summary>
        /// <param name="x">the first source vector.</param>
        /// <param name="y">the second source vector.</param>
        /// <param name="A">the matrix to hold the resultsd Set this parameter to <i>null</i> to indicate that a new result matrix shall be constructed.</param>
        /// <returns>A (for convenience only).</returns>
        public static DoubleMatrix2D MultOuter(DoubleMatrix1D x, DoubleMatrix1D y, DoubleMatrix2D A)
        {
            int rows    = x.Size;
            int columns = y.Size;

            if (A == null)
            {
                A = x.Like2D(rows, columns);
            }
            if (A.Rows != rows || A.Columns != columns)
            {
                throw new ArgumentException();
            }

            for (int row = rows; --row >= 0;)
            {
                A.ViewRow(row).Assign(y);
            }

            for (int column = columns; --column >= 0;)
            {
                A.ViewColumn(column).Assign(x, BinaryFunctions.Mult);
            }
            return(A);
        }
コード例 #3
0
        /// <summary>
        /// Constructs and returns the covariance matrix of the given matrix.
        /// The covariance matrix is a square, symmetric matrix consisting of nothing but covariance coefficientsd
        /// The rows and the columns represent the variables, the cells represent covariance coefficientsd
        /// The diagonal cells (i.ed the covariance between a variable and itself) will equal the variances.
        /// The covariance of two column vectors x and y is given by <i>cov(x,y) = (1/n) * Sum((x[i]-mean(x)) * (y[i]-mean(y)))</i>.
        /// See the <A HREF="http://www.cquest.utoronto.ca/geog/ggr270y/notes/not05efg.html"> math definition</A>.
        /// Compares two column vectors at a timed Use dice views to compare two row vectors at a time.
        /// </summary>
        /// <param name="matrix">any matrix; a column holds the values of a given variable.</param>
        /// <returns>the covariance matrix (<i>n x n, n=matrix.Columns</i>).</returns>
        public static DoubleMatrix2D Covariance(DoubleMatrix2D matrix)
        {
            int            rows       = matrix.Rows;
            int            columns    = matrix.Columns;
            DoubleMatrix2D covariance = new DenseDoubleMatrix2D(columns, columns);

            double[]         sums = new double[columns];
            DoubleMatrix1D[] cols = new DoubleMatrix1D[columns];
            for (int i = columns; --i >= 0;)
            {
                cols[i] = matrix.ViewColumn(i);
                sums[i] = cols[i].ZSum();
            }

            for (int i = columns; --i >= 0;)
            {
                for (int j = i + 1; --j >= 0;)
                {
                    double sumOfProducts = cols[i].ZDotProduct(cols[j]);
                    double cov           = (sumOfProducts - sums[i] * sums[j] / rows) / rows;
                    covariance[i, j] = cov;
                    covariance[j, i] = cov; // symmetric
                }
            }
            return(covariance);
        }
コード例 #4
0
ファイル: Sorting.cs プロジェクト: cobaltblueocean/Colt.NET
        /// <summary>
        /// Sorts the matrix rows into ascending order, according to the <i>natural ordering</i> of the matrix values in the given column.
        /// </summary>
        /// <param name="matrix">
        /// The matrix to be sorted.
        /// </param>
        /// <param name="column">
        /// The index of the column inducing the order.
        /// </param>
        /// <returns>
        /// A new matrix view having rows sorted by the given column.
        /// </returns>
        /// <exception cref="IndexOutOfRangeException">
        /// If <i>column &lt; 0 || column &gt;= matrix.columns()</i>.
        /// </exception>
        public DoubleMatrix2D Sort(DoubleMatrix2D matrix, int column)
        {
            if (column < 0 || column >= matrix.Columns)
            {
                throw new IndexOutOfRangeException("column=" + column + ", matrix=" + AbstractFormatter.Shape(matrix));
            }

            var rowIndexes = new int[matrix.Rows]; // row indexes to reorder instead of matrix itself

            for (int i = rowIndexes.Length; --i >= 0;)
            {
                rowIndexes[i] = i;
            }

            DoubleMatrix1D col = matrix.ViewColumn(column);

            RunSort(
                rowIndexes,
                0,
                rowIndexes.Length,
                (a, b) =>
            {
                double av = col[a];
                double bv = col[b];
                if (Double.IsNaN(av) || Double.IsNaN(bv))
                {
                    return(CompareNaN(av, bv));                                          // swap NaNs to the end
                }
                return(av < bv ? -1 : (av == bv ? 0 : 1));
            });

            // view the matrix according to the reordered row indexes
            // take all columns in the original order
            return(matrix.ViewSelection(rowIndexes, null));
        }
コード例 #5
0
ファイル: Algebra.cs プロジェクト: cobaltblueocean/Colt.NET
        /// <summary>
        /// Returns the one-norm of matrix <i>A</i>, which is the maximum absolute column sum.
        /// </summary>
        /// <param name="A">The matrix A</param>
        /// <returns>The one-norm of A.</returns>
        public static double Norm1(DoubleMatrix2D A)
        {
            double max = 0;

            for (int column = A.Columns; --column >= 0;)
            {
                max = System.Math.Max(max, Norm1(A.ViewColumn(column)));
            }
            return(max);
        }
コード例 #6
0
        /// <summary>
        /// Same as <see cref="Cern.Colt.Partitioning.Partition(int[], int, int, int[], int, int, int[])"/>
        /// except that it <i>synchronously</i> partitions the rows of the given matrix by the values of the given matrix column;
        /// This is essentially the same as partitioning a list of composite objects by some instance variable;
        /// In other words, two entire rows of the matrix are swapped, whenever two column values indicate so.
        /// <p>
        /// Let's say, a "row" is an "object" (tuple, d-dimensional point).
        /// A "column" is the list of "object" values of a given variable (field, dimension).
        /// A "matrix" is a list of "objects" (tuples, points).
        /// <p>
        /// Now, rows (objects, tuples) are partially sorted according to their values in one given variable (dimension).
        /// Two entire rows of the matrix are swapped, whenever two column values indicate so.
        /// <p>
        /// Note that arguments are not checked for validity.
        ///
        /// </summary>
        /// <param name="matrix">
        /// the matrix to be partitioned.
        /// </param>
        /// <param name="rowIndexes">
        /// the index of the i-th row; is modified by this method to reflect partitioned indexes.
        /// </param>
        /// <param name="rowFrom">
        /// the index of the first row (inclusive).
        /// </param>
        /// <param name="rowTo">
        /// the index of the last row (inclusive).
        /// </param>
        /// <param name="column">
        /// the index of the column to partition on.
        /// </param>
        /// <param name="splitters">
        /// the values at which the rows shall be split into intervals.
        /// Must be sorted ascending and must not contain multiple identical values.
        /// These preconditions are not checked; be sure that they are met.
        /// </param>
        /// <param name="splitFrom">
        /// the index of the first splitter element to be considered.
        /// </param>
        /// <param name="splitTo">
        /// the index of the last splitter element to be considered.
        /// The method considers the splitter elements<i>splitters[splitFrom] .d splitters[splitTo]</i>.
        /// </param>
        /// <param name="splitIndexes">
        /// a list into which this method fills the indexes of rows delimiting intervals.
        /// Upon return <i>splitIndexes[splitFrom..splitTo]</i> will be set accordingly.
        /// Therefore, must satisfy <i>splitIndexes.Length >= splitters.Length</i>.
        /// </param>
        /// <example>
        /// <table border="1" cellspacing="0">
        ///           <tr nowrap>
        ///             <td valign="top"><i>8 x 3 matrix:<br>
        ///               23, 22, 21<br>
        ///               20, 19, 18<br>
        ///               17, 16, 15<br>
        ///               14, 13, 12<br>
        ///               11, 10, 9<br>
        ///               8,  7,  6<br>
        ///               5,  4,  3<br>
        ///               2,  1,  0 </i></td>
        ///             <td align="left" valign="top">
        ///               <p><i>column = 0;<br>
        ///                 rowIndexes = {0,1,2,.d,matrix.Rows-1};
        ///                 rowFrom = 0;<br>
        ///                 rowTo = matrix.Rows-1;<br>
        ///                 splitters = {5,10,12}<br>
        ///                 c = 0; <br>
        ///                 d = splitters.Length-1;<br>
        ///                 partition(matrix,rowIndexes,rowFrom,rowTo,column,splitters,c,d,splitIndexes);<br>
        ///                 ==><br>
        ///                 splitIndexes == {0, 2, 3}<br>
        ///                 rowIndexes == {7, 6, 5, 4, 0, 1, 2, 3}</i></p>
        ///               </td>
        ///             <td valign="top">
        ///               The matrix IS NOT REORDERED.<br>
        ///               Here is how it would look<br>
        ///               like, if it would be reordered<br>
        ///               accoring to <i>rowIndexes</i>.<br>
        ///               <i>8 x 3 matrix:<br>
        ///               2,  1,  0<br>
        ///               5,  4,  3<br>
        ///               8,  7,  6<br>
        ///               11, 10, 9<br>
        ///               23, 22, 21<br>
        ///               20, 19, 18<br>
        ///               17, 16, 15<br>
        ///               14, 13, 12 </i></td>
        ///           </tr>
        /// </table>
        /// </example>
        public static void Partition(DoubleMatrix2D matrix, int[] rowIndexes, int rowFrom, int rowTo, int column, double[] splitters, int splitFrom, int splitTo, int[] splitIndexes)
        {
            if (rowFrom < 0 || rowTo >= matrix.Rows || rowTo >= rowIndexes.Length)
            {
                throw new ArgumentException();
            }
            if (column < 0 || column >= matrix.Columns)
            {
                throw new ArgumentException();
            }
            if (splitFrom < 0 || splitTo >= splitters.Length)
            {
                throw new ArgumentException();
            }
            if (splitIndexes.Length < splitters.Length)
            {
                throw new ArgumentException();
            }

            // this one knows how to swap two row indexes (a,b)
            int[]   g       = rowIndexes;
            Swapper swapper = new Swapper((b, c) =>
            {
                int tmp = g[b]; g[b] = g[c]; g[c] = tmp;
            });

            // compare splitter[a] with columnView[rowIndexes[b]]
            DoubleMatrix1D columnView = matrix.ViewColumn(column);
            IntComparator  comp       = new IntComparator((a, b) =>
            {
                double av = splitters[a];
                double bv = columnView[g[b]];
                return(av < bv ? -1 : (av == bv ? 0 : 1));
            });

            // compare columnView[rowIndexes[a]] with columnView[rowIndexes[b]]
            IntComparator comp2 = new IntComparator((a, b) =>
            {
                double av = columnView[g[a]];
                double bv = columnView[g[b]];
                return(av < bv ? -1 : (av == bv ? 0 : 1));
            });

            // compare splitter[a] with splitter[b]
            IntComparator comp3 = new IntComparator((a, b) =>
            {
                double av = splitters[a];
                double bv = splitters[b];
                return(av < bv ? -1 : (av == bv ? 0 : 1));
            });

            // generic partitioning does the main work of reordering row indexes
            Cern.Colt.Partitioning.GenericPartition(rowFrom, rowTo, splitFrom, splitTo, splitIndexes, comp, comp2, comp3, swapper);
        }
コード例 #7
0
        /// <summary>
        /// A matrix <i>A</i> is <i>diagonally dominant by column</i> if the absolute value of each diagonal element is larger than the sum of the absolute values of theoff-diagonal elements in the corresponding column.
        /// <i>returns true if for all i: abs(A[i,i]) &gt; Sum(abs(A[j,i])); j != i.</i>
        /// Matrix may but need not be square.
        /// <p>
        /// Note: Ignores tolerance.
        /// <summary>
        public Boolean IsDiagonallyDominantByColumn(DoubleMatrix2D A)
        {
            Cern.Jet.Math.Functions F = Cern.Jet.Math.Functions.functions;
            double epsilon            = Tolerance;
            int    min = System.Math.Min(A.Rows, A.Columns);

            for (int i = min; --i >= 0;)
            {
                double diag = System.Math.Abs(A[i, i]);
                diag += diag;
                if (diag <= A.ViewColumn(i).Aggregate(F2.Plus, F1.Abs))
                {
                    return(false);
                }
            }
            return(true);
        }
コード例 #8
0
        /// <summary>
        /// Modifies the given matrix square matrix<i>A</i> such that it is diagonally dominant by row and column, hence non-singular, hence invertible.
        /// For testing purposes only.
        /// <summary>
        ///<param name = "A" > the square matrix to modify.</param>
        ///<exception cref = "ArgumentException" >if <i>!isSquare(A)</i>. </exception>
        public void GenerateNonSingular(DoubleMatrix2D A)
        {
            CheckSquare(A);
            var F   = Cern.Jet.Math.Functions.functions;
            int min = System.Math.Min(A.Rows, A.Columns);

            for (int i = min; --i >= 0;)
            {
                A[i, i] = 0;
            }
            for (int i = min; --i >= 0;)
            {
                double rowSum = A.ViewRow(i).Aggregate(F2.Plus, F1.Abs);
                double colSum = A.ViewColumn(i).Aggregate(F2.Plus, F1.Abs);
                A[i, i] = System.Math.Max(rowSum, colSum) + i + 1;
            }
        }
コード例 #9
0
        /// <summary>
        /// Applies the given aggregation functions to each column and stores the results in a the result matrix.
        /// If matrix has shape <i>m x n</i>, then result must have shape <i>aggr.Length x n</i>.
        /// Tip: To do aggregations on rows use dice views (transpositions), as in <i>aggregate(matrix.viewDice(),aggr,result.viewDice())</i>.
        /// </summary>
        /// <param name="matrix">any matrix; a column holds the values of a given variable.</param>
        /// <param name="aggr">the aggregation functions to be applied to each column.</param>
        /// <param name="result">the matrix to hold the aggregation results.</param>
        /// <returns><i>result</i> (for convenience only).</returns>
        /// <see cref="Formatter"/>
        /// <see cref="Hep.Aida.Bin.BinFunction1D"/>
        /// <see cref="Hep.Aida.Bin.BinFunctions1D"/>
        public static DoubleMatrix2D Aggregate(DoubleMatrix2D matrix, Hep.Aida.Bin.BinFunction1D[] aggr, DoubleMatrix2D result)
        {
            var bin      = new DynamicBin1D();
            var elements = new double[matrix.Rows];
            var values   = elements;

            for (int column = matrix.Columns; --column >= 0;)
            {
                matrix.ViewColumn(column).ToArray(ref elements); // copy column into values
                bin.Clear();
                bin.AddAllOf(new DoubleArrayList(values));
                for (int i = aggr.Length; --i >= 0;)
                {
                    result[i, column] = aggr[i](bin);
                }
            }
            return(result);
        }
コード例 #10
0
ファイル: Algebra.cs プロジェクト: cobaltblueocean/Colt.NET
        public static DoubleMatrix2D PermuteRows(DoubleMatrix2D A, int[] indexes, int[] work)
        {
            // check validity
            int size = A.Rows;

            if (indexes.Length != size)
            {
                throw new IndexOutOfRangeException("invalid permutation");
            }

            /*
             * int i=size;
             * int a;
             * while (--i >= 0 && (a=indexes[i])==i) if (a < 0 || a >= size) throw new IndexOutOfRangeException("invalid permutation");
             * if (i<0) return; // nothing to permute
             */

            int columns = A.Columns;

            if (columns < size / 10)
            { // quicker
                double[] doubleWork = new double[size];
                for (int j = A.Columns; --j >= 0;)
                {
                    Permute(A.ViewColumn(j), indexes, doubleWork);
                }
                return(A);
            }

            var swapper = new Cern.Colt.Swapper((a, b) =>
            {
                A.ViewRow(a).Swap(A.ViewRow(b));
            }
                                                );

            Cern.Colt.GenericPermuting.permute(indexes, swapper, work, null);
            return(A);
        }
コード例 #11
0
ファイル: Algebra.cs プロジェクト: cobaltblueocean/Colt.NET
        /// <summary>
        /// Copies the rows of the indicated columns into a new sub matrix.
        /// <i>sub[0..rowTo-rowFrom,0..columnIndexes.Length-1] = A[rowFrom..rowTo,columnIndexes(:)]</i>;
        /// The returned matrix is <i>not backed</i> by this matrix, so changes in the returned matrix are <i>not reflected</i> in this matrix, and vice-versa.
        /// </summary>
        /// <param name="A">the source matrix to copy from.</param>
        /// <param name="rowFrom">the index of the first row to copy (inclusive).</param>
        /// <param name="rowTo">the index of the last row to copy (inclusive).</param>
        /// <param name="columnIndexes">the indexes of the columns to copyd May be unsorted.</param>
        /// <returns>a new sub matrix; with <i>sub.Rows==rowTo-rowFrom+1; sub.Columns==columnIndexes.Length</i>.</returns>
        /// <exception cref="IndexOutOfRangeException">if <i>rowFrom &lt; 0 || rowTo-rowFrom + 1 &lt; 0 || rowTo + 1 > matrix.Rows || for any col = columnIndexes[i]: col &lt; 0 || col >= matrix.Columns</i>.</exception>
        private static DoubleMatrix2D SubMatrix(DoubleMatrix2D A, int rowFrom, int rowTo, int[] columnIndexes)
        {
            if (rowTo - rowFrom >= A.Rows)
            {
                throw new IndexOutOfRangeException("Too many rows");
            }
            int height  = rowTo - rowFrom + 1;
            int columns = A.Columns;

            A = A.ViewPart(rowFrom, 0, height, columns);
            DoubleMatrix2D sub = A.Like(height, columnIndexes.Length);

            for (int c = columnIndexes.Length; --c >= 0;)
            {
                int column = columnIndexes[c];
                if (column < 0 || column >= columns)
                {
                    throw new IndexOutOfRangeException("Illegal Index");
                }
                sub.ViewColumn(c).Assign(A.ViewColumn(column));
            }
            return(sub);
        }
コード例 #12
0
        /// <summary>
        /// Constructs and returns the distance matrix of the given matrix.
        /// The distance matrix is a square, symmetric matrix consisting of nothing but distance coefficientsd
        /// The rows and the columns represent the variables, the cells represent distance coefficientsd
        /// The diagonal cells (i.ed the distance between a variable and itself) will be zero.
        /// Compares two column vectors at a timed Use dice views to compare two row vectors at a time.
        /// </summary>
        /// <param name="matrix">any matrix; a column holds the values of a given variable (vector).</param>
        /// <param name="distanceFunction">(EUCLID, CANBERRA, ..d, or any user defined distance function operating on two vectors).</param>
        /// <returns>the distance matrix (<i>n x n, n=matrix.Columns</i>).</returns>
        public static DoubleMatrix2D Distance(DoubleMatrix2D matrix, VectorVectorFunction distanceFunction)
        {
            int            columns  = matrix.Columns;
            DoubleMatrix2D distance = new DenseDoubleMatrix2D(columns, columns);

            // cache views
            DoubleMatrix1D[] cols = new DoubleMatrix1D[columns];
            for (int i = columns; --i >= 0;)
            {
                cols[i] = matrix.ViewColumn(i);
            }

            // work out all permutations
            for (int i = columns; --i >= 0;)
            {
                for (int j = i; --j >= 0;)
                {
                    double d = distanceFunction(cols[i], cols[j]);
                    distance[i, j] = d;
                    distance[j, i] = d; // symmetric
                }
            }
            return(distance);
        }
コード例 #13
0
        /// <summary>
        /// Constructs and returns a new QR decomposition object;  computed by Householder reflections;
        /// The decomposed matrices can be retrieved via instance methods of the returned decomposition object.
        /// Return a decomposition object to access <i>R</i> and the Householder vectors <i>H</i>, and to compute <i>Q</i>.
        /// </summary>
        /// <param name="A">A rectangular matrix.</param>
        /// <exception cref="ArgumentException">if <i>A.Rows &lt; A.Columns</i>.</exception>
        public QRDecomposition(DoubleMatrix2D A)
        {
            Property.DEFAULT.CheckRectangular(A);

            Functions F = Functions.functions;

            // Initialize.
            QR    = A.Copy();
            m     = A.Rows;
            n     = A.Columns;
            Rdiag = A.Like1D(n);
            //Rdiag = new double[n];
            DoubleDoubleFunction hypot = Algebra.HypotFunction();

            // precompute and cache some views to avoid regenerating them time and again
            DoubleMatrix1D[] QRcolumns     = new DoubleMatrix1D[n];
            DoubleMatrix1D[] QRcolumnsPart = new DoubleMatrix1D[n];
            for (int k = 0; k < n; k++)
            {
                QRcolumns[k]     = QR.ViewColumn(k);
                QRcolumnsPart[k] = QR.ViewColumn(k).ViewPart(k, m - k);
            }

            // Main loop.
            for (int k = 0; k < n; k++)
            {
                //DoubleMatrix1D QRcolk = QR.ViewColumn(k).ViewPart(k,m-k);
                // Compute 2-norm of k-th column without under/overflow.
                double nrm = 0;
                //if (k<m) nrm = QRcolumnsPart[k].aggregate(hypot,F.identity);

                for (int i = k; i < m; i++)
                { // fixes bug reported by [email protected]
                    nrm = Algebra.Hypot(nrm, QR[i, k]);
                }


                if (nrm != 0.0)
                {
                    // Form k-th Householder vector.
                    if (QR[k, k] < 0)
                    {
                        nrm = -nrm;
                    }
                    QRcolumnsPart[k].Assign(F2.Div(nrm));

                    /*
                     * for (int i = k; i < m; i++) {
                     * QR[i][k] /= nrm;
                     * }
                     */

                    QR[k, k] = QR[k, k] + 1;

                    // Apply transformation to remaining columns.
                    for (int j = k + 1; j < n; j++)
                    {
                        DoubleMatrix1D QRcolj = QR.ViewColumn(j).ViewPart(k, m - k);
                        double         s      = QRcolumnsPart[k].ZDotProduct(QRcolj);

                        /*
                         * // fixes bug reported by John Chambers
                         * DoubleMatrix1D QRcolj = QR.ViewColumn(j).ViewPart(k,m-k);
                         * double s = QRcolumnsPart[k].ZDotProduct(QRcolumns[j]);
                         * double s = 0.0;
                         * for (int i = k; i < m; i++) {
                         * s += QR[i][k]*QR[i][j];
                         * }
                         */
                        s = -s / QR[k, k];
                        //QRcolumnsPart[j].Assign(QRcolumns[k], F.PlusMult(s));

                        for (int i = k; i < m; i++)
                        {
                            QR[i, j] = QR[i, j] + s * QR[i, k];
                        }
                    }
                }
                Rdiag[k] = -nrm;
            }
        }
コード例 #14
0
        public void Decompose(DoubleMatrix2D A)
        {
            int CUT_OFF = 10;

            // setup
            LU = A;
            int m = A.Rows;
            int n = A.Columns;

            // setup pivot vector
            if (this.piv == null || this.piv.Length != m)
            {
                this.piv = new int[m];
            }
            for (int i = m; --i >= 0;)
            {
                piv[i] = i;
            }
            pivsign = 1;

            if (m * n == 0)
            {
                LU = LU;
                return; // nothing to do
            }

            //precompute and cache some views to avoid regenerating them time and again
            DoubleMatrix1D[] LUrows = new DoubleMatrix1D[m];
            for (int i = 0; i < m; i++)
            {
                LUrows[i] = LU.ViewRow(i);
            }

            IntArrayList   nonZeroIndexes = new IntArrayList();      // sparsity
            DoubleMatrix1D LUcolj         = LU.ViewColumn(0).Like(); // blocked column j

            Cern.Jet.Math.Mult multFunction = Cern.Jet.Math.Mult.CreateInstance(0);

            // Outer loop.
            for (int j = 0; j < n; j++)
            {
                // blocking (make copy of j-th column to localize references)
                LUcolj.Assign(LU.ViewColumn(j));

                // sparsity detection
                int maxCardinality = m / CUT_OFF; // == heuristic depending on speedup
                LUcolj.GetNonZeros(nonZeroIndexes, null, maxCardinality);
                int     cardinality = nonZeroIndexes.Count;
                Boolean sparse      = (cardinality < maxCardinality);

                // Apply previous transformations.
                for (int i = 0; i < m; i++)
                {
                    int    kmax = System.Math.Min(i, j);
                    double s;
                    if (sparse)
                    {
                        s = LUrows[i].ZDotProduct(LUcolj, 0, kmax, nonZeroIndexes);
                    }
                    else
                    {
                        s = LUrows[i].ZDotProduct(LUcolj, 0, kmax);
                    }
                    double before = LUcolj[i];
                    double after  = before - s;
                    LUcolj[i] = after; // LUcolj is a copy
                    LU[i, j]  = after; // this is the original
                    if (sparse)
                    {
                        if (before == 0 && after != 0)
                        { // nasty bug fixed!
                            int pos = nonZeroIndexes.BinarySearch(i);
                            pos = -pos - 1;
                            nonZeroIndexes.Insert(pos, i);
                        }
                        if (before != 0 && after == 0)
                        {
                            nonZeroIndexes.Remove(nonZeroIndexes.BinarySearch(i));
                        }
                    }
                }

                // Find pivot and exchange if necessary.
                int p = j;
                if (p < m)
                {
                    double max = System.Math.Abs(LUcolj[p]);
                    for (int i = j + 1; i < m; i++)
                    {
                        double v = System.Math.Abs(LUcolj[i]);
                        if (v > max)
                        {
                            p   = i;
                            max = v;
                        }
                    }
                }
                if (p != j)
                {
                    LUrows[p].Swap(LUrows[j]);
                    int k = piv[p]; piv[p] = piv[j]; piv[j] = k;
                    pivsign = -pivsign;
                }

                // Compute multipliers.
                double jj;
                if (j < m && (jj = LU[j, j]) != 0.0)
                {
                    multFunction.Multiplicator = 1 / jj;
                    LU.ViewColumn(j).ViewPart(j + 1, m - (j + 1)).Assign(multFunction);
                }
            }
            LU = LU;
        }