Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <summary>
        /// Returns a string representation of the given matrix.
        /// </summary>
        /// <param name="matrix">
        /// The matrix to convert.
        /// </param>
        /// <returns>
        /// A string representation of the given matrix.
        /// </returns>
        public string ToString(DoubleMatrix1D matrix)
        {
            DoubleMatrix2D easy = matrix.Like2D(1, matrix.Size);

            easy.ViewRow(0).Assign(matrix);
            return(ToString(easy));
        }
Пример #3
0
 public void Dger(double alpha, DoubleMatrix1D x, DoubleMatrix1D y, DoubleMatrix2D A)
 {
     Cern.Jet.Math.PlusMult fun = new Cern.Jet.Math.PlusMult(0);
     for (int i = A.Rows; --i >= 0;)
     {
         fun.Multiplicator = alpha * x[i];
         A.ViewRow(i).Assign(y, fun);
     }
 }
Пример #4
0
 public void Dswap(DoubleMatrix2D A, DoubleMatrix2D B)
 {
     //B.Swap(A); not yet implemented
     A.CheckShape(B);
     for (int i = A.Rows; --i >= 0;)
     {
         A.ViewRow(i).Swap(B.ViewRow(i));
     }
 }
Пример #5
0
        /// <summary>
        /// Returns a string representations of all cells; no alignment considered.
        /// </summary>
        /// <param name="matrix">
        /// The matrix.
        /// </param>
        /// <returns>
        /// A string representation of all cells.
        /// </returns>
        public string[][] Format(DoubleMatrix2D matrix)
        {
            var strings = new string[matrix.Rows][];

            for (int row = matrix.Rows; --row >= 0;)
            {
                strings[row] = FormatRow(matrix.ViewRow(row));
            }
            return(strings);
        }
Пример #6
0
        /// <summary>
        /// Returns the infinity norm of matrix <i>A</i>, which is the maximum absolute row sum.
        /// </summary>
        /// <param name="A">The matrix A.</param>
        /// <returns>The infinity norm of matrix <i>A</i></returns>
        public static double NormInfinity(DoubleMatrix2D A)
        {
            double max = 0;

            for (int row = A.Rows; --row >= 0;)
            {
                //max = System.Math.Max(max, normInfinity(A.ViewRow(row)));
                max = System.Math.Max(max, Norm1(A.ViewRow(row)));
            }
            return(max);
        }
Пример #7
0
        /// <summary>
        /// Constructs and returns a new Cholesky decomposition object for a symmetric and positive definite matrix;
        /// The decomposed matrices can be retrieved via instance methods of the returned decomposition object.
        ///
        /// Return a structure to access <i>L</i> and <i>isSymmetricPositiveDefinite</i> flag.
        /// </summary>
        /// <param name="A">Square, symmetric matrix.</param>
        /// <exception cref="ArgumentException">if <i>A</i> is not square.</exception>
        public CholeskyDecomposition(DoubleMatrix2D A)
        {
            Property.DEFAULT.CheckSquare(A);
            // Initialize.
            //double[][] A = Arg.getArray();

            n = A.Rows;
            //L = new double[n][n];
            mL = A.Like(n, n);
            isSymmetricPositiveDefinite = (A.Columns == n);

            //precompute and cache some views to avoid regenerating them time and again
            DoubleMatrix1D[] Lrows = new DoubleMatrix1D[n];
            for (int j = 0; j < n; j++)
            {
                Lrows[j] = mL.ViewRow(j);
            }

            // Main loop.
            for (int j = 0; j < n; j++)
            {
                //double[] Lrowj = L[j];
                //DoubleMatrix1D Lrowj = L.ViewRow(j);
                double d = 0.0;
                for (int k = 0; k < j; k++)
                {
                    //double[] Lrowk = L[k];
                    double s = Lrows[k].ZDotProduct(Lrows[j], 0, k);

                    /*
                     * DoubleMatrix1D Lrowk = L.ViewRow(k);
                     * double s = 0.0;
                     * for (int i = 0; i < k; i++) {
                     * s += Lrowk.getQuick(i)*Lrowj.getQuick(i);
                     * }
                     */
                    s           = (A[j, k] - s) / mL[k, k];
                    Lrows[j][k] = s;
                    d           = d + s * s;
                    isSymmetricPositiveDefinite = isSymmetricPositiveDefinite && (A[k, j] == A[j, k]);
                }
                d = A[j, j] - d;
                isSymmetricPositiveDefinite = isSymmetricPositiveDefinite && (d > 0.0);
                mL[j, j] = System.Math.Sqrt(System.Math.Max(d, 0.0));

                for (int k = j + 1; k < n; k++)
                {
                    mL[j, k] = 0.0;
                }
            }
        }
Пример #8
0
        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);
        }
Пример #9
0
        /// <summary>
        /// Solves <i>A*X = B</i>; returns <i>X</i>.
        /// </summary>
        /// <param name="B">A Matrix with as many rows as <i>A</i> and any number of columns.</param>
        /// <returns><i>X</i> so that <i>L*L'*X = B</i>.</returns>
        /// <exception cref="ArgumentException">if <i>B.Rows != A.Rows</i>.</exception>
        /// <exception cref="ArgumentException">if <i>!isSymmetricPositiveDefinite()</i>.</exception>
        private DoubleMatrix2D XXXsolveBuggy(DoubleMatrix2D B)
        {
            var F = Cern.Jet.Math.Functions.functions;

            if (B.Rows != n)
            {
                throw new ArgumentException(Cern.LocalizedResources.Instance().Exception_MatrixRowDimensionsMustAgree);
            }
            if (!isSymmetricPositiveDefinite)
            {
                throw new ArgumentException(Cern.LocalizedResources.Instance().Exception_MatrixIsNotSymmetricPositiveDefinite);
            }

            // Copy right hand side.
            DoubleMatrix2D X  = B.Copy();
            int            nx = B.Columns;

            // precompute and cache some views to avoid regenerating them time and again
            DoubleMatrix1D[] Xrows = new DoubleMatrix1D[n];
            for (int k = 0; k < n; k++)
            {
                Xrows[k] = X.ViewRow(k);
            }

            // Solve L*Y = B;
            for (int k = 0; k < n; k++)
            {
                for (int i = k + 1; i < n; i++)
                {
                    // X[i,j] -= X[k,j]*L[i,k]
                    Xrows[i].Assign(Xrows[k], F2.MinusMult(mL[i, k]));
                }
                Xrows[k].Assign(F1.Div(mL[k, k]));
            }

            // Solve L'*X = Y;
            for (int k = n - 1; k >= 0; k--)
            {
                Xrows[k].Assign(F1.Div(mL[k, k]));
                for (int i = 0; i < k; i++)
                {
                    // X[i,j] -= X[k,j]*L[k,i]
                    Xrows[i].Assign(Xrows[k], F2.MinusMult(mL[k, i]));
                }
            }
            return(X);
        }
Пример #10
0
        /// <summary>
        /// A matrix <i>A</i> is <i>diagonally dominant by row</i> if the absolute value of each diagonal element is larger than the sum of the absolute values of the off-diagonal elements in the corresponding row.
        /// <i>returns true if for all i: abs(A[i,i]) &gt; Sum(abs(A[i,j])); j != i.</i>
        /// Matrix may but need not be square.
        /// <p>
        /// Note: Ignores tolerance.
        /// <summary>
        public Boolean IsDiagonallyDominantByRow(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.ViewRow(i).Aggregate(F2.Plus, F1.Abs))
                {
                    return(false);
                }
            }
            return(true);
        }
Пример #11
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;
            }
        }
Пример #12
0
        /// <summary>
        /// Copies the columns of the indicated rows into a new sub matrix.
        /// <i>sub[0..rowIndexes.Length-1,0..columnTo-columnFrom] = A[rowIndexes(:),columnFrom..columnTo]</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="rowIndexes">the indexes of the rows to copyd May be unsorted.</param>
        /// <param name="columnFrom">the index of the first column to copy (inclusive).</param>
        /// <param name="columnTo">the index of the last column to copy (inclusive).</param>
        /// <returns>a new sub matrix; with <i>sub.Rows==rowIndexes.Length; sub.Columns==columnTo-columnFrom+1</i>.</returns>
        /// <exception cref="IndexOutOfRangeException">if <i>columnFrom &lt; 0 || columnTo-columnFrom+1 &lt; 0 || columnTo+1>matrix.Columns || for any row=rowIndexes[i]: row  &lt;  0 || row >= matrix.Rows</i>.</exception>
        private static DoubleMatrix2D SubMatrix(DoubleMatrix2D A, int[] rowIndexes, int columnFrom, int columnTo)
        {
            int width = columnTo - columnFrom + 1;
            int rows  = A.Rows;

            A = A.ViewPart(0, columnFrom, rows, width);
            DoubleMatrix2D sub = A.Like(rowIndexes.Length, width);

            for (int r = rowIndexes.Length; --r >= 0;)
            {
                int row = rowIndexes[r];
                if (row < 0 || row >= rows)
                {
                    throw new IndexOutOfRangeException("Illegal Index");
                }
                sub.ViewRow(r).Assign(A.ViewRow(row));
            }
            return(sub);
        }
Пример #13
0
        /// <summary>
        /// Sorts the matrix rows according to the order induced by the specified comparator.
        /// </summary>
        /// <param name="matrix">
        /// The matrix to be sorted.
        /// </param>
        /// <param name="c">
        /// The comparator to determine the order.
        /// </param>
        /// <returns>
        /// A new matrix view having rows sorted as specified.
        /// </returns>
        public DoubleMatrix2D Sort(DoubleMatrix2D matrix, DoubleMatrix1DComparator c)
        {
            var rowIndexes = new int[matrix.Rows]; // row indexes to reorder instead of matrix itself

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

            var views = new DoubleMatrix1D[matrix.Rows]; // precompute views for speed

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

            RunSort(rowIndexes, 0, rowIndexes.Length, (a, b) => c(views[a], views[b]));

            // view the matrix according to the reordered row indexes
            // take all columns in the original order
            return(matrix.ViewSelection(rowIndexes, null));
        }
        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;
        }
        public void Solve(DoubleMatrix2D B)
        {
            int CUT_OFF = 10;
            //algebra.property().checkRectangular(LU);
            int m = M;
            int n = N;

            if (B.Rows != m)
            {
                throw new ArgumentException("Matrix row dimensions must agree.");
            }
            if (!this.IsNonsingular)
            {
                throw new ArgumentException("Matrix is singular.");
            }


            // right hand side with pivoting
            // Matrix Xmat = B.getMatrix(piv,0,nx-1);
            if (this.work1 == null || this.work1.Length < m)
            {
                this.work1 = new int[m];
            }
            //if (this.work2 == null || this.work2.Length < m) this.work2 = new int[m];
            Algebra.PermuteRows(B, this.piv, this.work1);

            if (m * n == 0)
            {
                return;             // nothing to do
            }
            int nx = B.Columns;

            //precompute and cache some views to avoid regenerating them time and again
            DoubleMatrix1D[] Brows = new DoubleMatrix1D[n];
            for (int k = 0; k < n; k++)
            {
                Brows[k] = B.ViewRow(k);
            }

            // transformations
            Cern.Jet.Math.Mult     div       = Cern.Jet.Math.Mult.Div(0);
            Cern.Jet.Math.PlusMult minusMult = Cern.Jet.Math.PlusMult.MinusMult(0);

            IntArrayList   nonZeroIndexes = new IntArrayList();                              // sparsity
            DoubleMatrix1D Browk          = Cern.Colt.Matrix.DoubleFactory1D.Dense.Make(nx); // blocked row k

            // Solve L*Y = B(piv,:)
            for (int k = 0; k < n; k++)
            {
                // blocking (make copy of k-th row to localize references)
                Browk.Assign(Brows[k]);

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

                for (int i = k + 1; i < n; i++)
                {
                    //for (int j = 0; j < nx; j++) B[i][j] -= B[k][j]*LU[i][k];
                    //for (int j = 0; j < nx; j++) B.set(i,j, B.Get(i,j) - B.Get(k,j)*LU.Get(i,k));

                    minusMult.Multiplicator = -LU[i, k];
                    if (minusMult.Multiplicator != 0)
                    {
                        if (sparse)
                        {
                            Brows[i].Assign(Browk, minusMult, nonZeroIndexes);
                        }
                        else
                        {
                            Brows[i].Assign(Browk, minusMult);
                        }
                    }
                }
            }

            // Solve U*B = Y;
            for (int k = n - 1; k >= 0; k--)
            {
                // for (int j = 0; j < nx; j++) B[k][j] /= LU[k][k];
                // for (int j = 0; j < nx; j++) B.set(k,j, B.Get(k,j) / LU.Get(k,k));
                div.Multiplicator = 1 / LU[k, k];
                Brows[k].Assign(div);

                // blocking
                if (Browk == null)
                {
                    Browk = Cern.Colt.Matrix.DoubleFactory1D.Dense.Make(B.Columns);
                }
                Browk.Assign(Brows[k]);

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

                //Browk.GetNonZeros(nonZeroIndexes,null);
                //Boolean sparse = nonZeroIndexes.Count < nx/10;

                for (int i = 0; i < k; i++)
                {
                    // for (int j = 0; j < nx; j++) B[i][j] -= B[k][j]*LU[i][k];
                    // for (int j = 0; j < nx; j++) B.set(i,j, B.Get(i,j) - B.Get(k,j)*LU.Get(i,k));

                    minusMult.Multiplicator = -LU[i, k];
                    if (minusMult.Multiplicator != 0)
                    {
                        if (sparse)
                        {
                            Brows[i].Assign(Browk, minusMult, nonZeroIndexes);
                        }
                        else
                        {
                            Brows[i].Assign(Browk, minusMult);
                        }
                    }
                }
            }
        }
        public override DoubleMatrix2D ZMult(DoubleMatrix2D B, DoubleMatrix2D C, double alpha, double beta, Boolean transposeA, Boolean transposeB)
        {
            if (transposeB)
            {
                B = B.ViewDice();
            }
            int m = Rows;
            int n = Columns;

            if (transposeA)
            {
                m = Columns;
                n = Rows;
            }
            int     p      = B.Columns;
            Boolean ignore = (C == null);

            if (C == null)
            {
                C = new DenseDoubleMatrix2D(m, p);
            }

            if (B.Rows != n)
            {
                throw new ArgumentException(String.Format(Cern.LocalizedResources.Instance().Exception_Matrix2DInnerDimensionMustAgree, ToStringShort(), (transposeB ? B.ViewDice() : B).ToStringShort()));
            }
            if (C.Rows != m || C.Columns != p)
            {
                throw new ArgumentException(String.Format(Cern.LocalizedResources.Instance().Exception_IncompatibleResultMatrix, ToStringShort(), (transposeB ? B.ViewDice() : B).ToStringShort(), C.ToStringShort()));
            }
            if (this == C || B == C)
            {
                throw new ArgumentException(Cern.LocalizedResources.Instance().Exception_MatricesMustNotBeIdentical);
            }

            if (!ignore)
            {
                C.Assign(F1.Mult(beta));
            }

            // cache views
            DoubleMatrix1D[] Brows = new DoubleMatrix1D[n];
            for (int i = n; --i >= 0;)
            {
                Brows[i] = B.ViewRow(i);
            }
            DoubleMatrix1D[] Crows = new DoubleMatrix1D[m];
            for (int i = m; --i >= 0;)
            {
                Crows[i] = C.ViewRow(i);
            }


            ForEachNonZero(
                new Cern.Colt.Function.IntIntDoubleFunction((i, j, value) =>
            {
                var fun = F2.PlusMult(value * alpha);
                //fun.multiplicator = value * alpha;
                if (!transposeA)
                {
                    Crows[i].Assign(Brows[j], fun);
                }
                else
                {
                    Crows[j].Assign(Brows[i], fun);
                }
                return(value);
            }
                                                            ));

            return(C);
        }
        public override DoubleMatrix2D ZMult(DoubleMatrix2D B, DoubleMatrix2D C, double alpha, double beta, Boolean transposeA, Boolean transposeB)
        {
            if (transposeB)
            {
                B = B.ViewDice();
            }
            int m = Rows;
            int n = Columns;

            if (transposeA)
            {
                m = Columns;
                n = Rows;
            }
            int     p      = B.Columns;
            Boolean ignore = (C == null);

            if (C == null)
            {
                C = new DenseDoubleMatrix2D(m, p);
            }

            if (B.Rows != n)
            {
                throw new ArgumentException("Matrix2D inner dimensions must agree:" + ToStringShort() + ", " + (transposeB ? B.ViewDice() : B).ToStringShort());
            }
            if (C.Rows != m || C.Columns != p)
            {
                throw new ArgumentException("Incompatibel result matrix: " + ToStringShort() + ", " + (transposeB ? B.ViewDice() : B).ToStringShort() + ", " + C.ToStringShort());
            }
            if (this == C || B == C)
            {
                throw new ArgumentException("Matrices must not be identical");
            }

            if (!ignore)
            {
                C.Assign(F1.Mult(beta));
            }

            // cache views
            DoubleMatrix1D[] Brows = new DoubleMatrix1D[n];
            for (int i = n; --i >= 0;)
            {
                Brows[i] = B.ViewRow(i);
            }
            DoubleMatrix1D[] Crows = new DoubleMatrix1D[m];
            for (int i = m; --i >= 0;)
            {
                Crows[i] = C.ViewRow(i);
            }


            ForEachNonZero(
                new Cern.Colt.Function.IntIntDoubleFunction((i, j, value) =>
            {
                var fun = F2.PlusMult(value * alpha);
                //fun.multiplicator = value * alpha;
                if (!transposeA)
                {
                    Crows[i].Assign(Brows[j], fun);
                }
                else
                {
                    Crows[j].Assign(Brows[i], fun);
                }
                return(value);
            }
                                                            ));

            return(C);
        }
        public override DoubleMatrix2D ZMult(DoubleMatrix2D B, DoubleMatrix2D C, double alpha, double beta, Boolean transposeA, Boolean transposeB)
        {
            if (transposeB)
            {
                B = B.ViewDice();
            }
            int m = Rows;
            int n = Columns;

            if (transposeA)
            {
                m = Columns;
                n = Rows;
            }
            int     p      = B.Columns;
            Boolean ignore = (C == null);

            if (C == null)
            {
                C = new DenseDoubleMatrix2D(m, p);
            }

            if (B.Rows != n)
            {
                throw new ArgumentException(String.Format(Cern.LocalizedResources.Instance().Exception_Matrix2DInnerDimensionMustAgree, ToStringShort(), (transposeB ? B.ViewDice() : B).ToStringShort()));
            }
            if (C.Rows != m || C.Columns != p)
            {
                throw new ArgumentException(String.Format(Cern.LocalizedResources.Instance().Exception_IncompatibleResultMatrix, ToStringShort(), (transposeB ? B.ViewDice() : B).ToStringShort(), C.ToStringShort()));
            }
            if (this == C || B == C)
            {
                throw new ArgumentException(Cern.LocalizedResources.Instance().Exception_MatricesMustNotBeIdentical);
            }

            if (!ignore)
            {
                C.Assign(F1.Mult(beta));
            }

            // cache views
            DoubleMatrix1D[] Brows = new DoubleMatrix1D[n];
            for (int i = n; --i >= 0;)
            {
                Brows[i] = B.ViewRow(i);
            }
            DoubleMatrix1D[] Crows = new DoubleMatrix1D[m];
            for (int i = m; --i >= 0;)
            {
                Crows[i] = C.ViewRow(i);
            }

            int[]    idx  = Indexes.ToArray();
            double[] vals = Values.ToArray();
            for (int i = Starts.Length - 1; --i >= 0;)
            {
                int low = Starts[i];
                for (int k = Starts[i + 1]; --k >= low;)
                {
                    int j   = idx[k];
                    var fun = F2.PlusMult(vals[k] * alpha);
                    //fun.Multiplicator = vals[k] * alpha;
                    if (!transposeA)
                    {
                        Crows[i].Assign(Brows[j], fun);
                    }
                    else
                    {
                        Crows[j].Assign(Brows[i], fun);
                    }
                }
            }

            return(C);
        }