/* * Z = log(X). or z = log(x) elementwise log */ public static void Log(SparseMatrix Z, SparseMatrix X) { // Dimension check if (Z.nCols != X.nCols || Z.nRows != X.nRows) { throw new Exception("Dimension mismatch."); } // Computation for (int IdxCol = 0; IdxCol < Z.nCols; IdxCol++) { var nNonzero = Z.SparseColumnVectors[IdxCol].nNonzero; var zKey = Z.SparseColumnVectors[IdxCol].Key; var xKey = X.SparseColumnVectors[IdxCol].Key; var zVal = Z.SparseColumnVectors[IdxCol].Val; var xVal = X.SparseColumnVectors[IdxCol].Val; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { if (zKey[IdxRow] != xKey[IdxRow]) { throw new Exception("Sparse patterns do not match in elementwise matrix multiplication."); } zVal[IdxRow] = (float) Math.Log( (double) (xVal[IdxRow])); } } }
/* * Compute the training error at the given batch */ public static int ComputeNumberOfErrors(SparseMatrix Dt, DenseMatrix y) { if (Dt.nCols != y.nCols) { throw new Exception("The numbers of samples from label and prediction do not match."); } int nTotError = 0; int[] PredictedClass = y.IndexOfVerticalMax(); for (int IdxCol = 0; IdxCol < Dt.nCols; IdxCol++) { if (Dt.SparseColumnVectors[IdxCol].Key[0] != PredictedClass[IdxCol]) { nTotError++; } } return nTotError; }
/* * Z = X * y (scalar) */ public static void ScalarMultiplyMatrix(SparseMatrix Z, SparseMatrix X, float y) { // Dimension check if (Z.nCols != X.nCols || Z.nRows != X.nRows) { throw new Exception("Dimension mismatch."); } // Computation Parallel.For(0, Z.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var zVal = Z.SparseColumnVectors[IdxCol].Val; var xVal = X.SparseColumnVectors[IdxCol].Val; int nNonzero = Z.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxRow] = xVal[IdxRow] * y; } }); }
public static void ElementwiseSquare(SparseMatrix Z) { int nCols = Z.nCols; int nRows = Z.nRows; Parallel.For(0, nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var zVal = Z.SparseColumnVectors[IdxCol].Val; int nNonzero = Z.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxRow] *= zVal[IdxRow]; } }); }
public static void ElementwiseMatrixMultiplyMatrix(SparseMatrix Z, SparseMatrix X, DenseMatrix Y) { // Dimension check if (X.nCols != Y.nCols || X.nRows != Y.nRows || Z.nCols != X.nCols || Z.nRows != X.nRows) { throw new Exception("Dimension mismatch during elementwise matrix multiplication."); } // Elementwise matrix multiplication Parallel.For(0, Z.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var zVal = Z.SparseColumnVectors[IdxCol].Val; var xVal = X.SparseColumnVectors[IdxCol].Val; var yVal = Y.DenseMatrixValue[IdxCol].VectorValue; var zKey = Z.SparseColumnVectors[IdxCol].Key; int nNonzero = Z.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxRow] = xVal[IdxRow] * yVal[zKey[IdxRow]]; } }); }
public static void VerticalMaxMatrix(DenseRowVector z, SparseMatrix X) { int zDim = z.Dim; var zVal = z.VectorValue; var XMat = X.SparseColumnVectors; Parallel.For(0, zDim, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { zVal[IdxCol] = XMat[IdxCol].Val.Max(); }); }
// This constructor performs deep copy from the source sparse matrix public SparseMatrix(SparseMatrix SourceSparseMatrix) { nRows = SourceSparseMatrix.nRows; nCols = SourceSparseMatrix.nCols; SparseColumnVectors = new SparseColumnVector[nCols]; for (int IdxCol = 0; IdxCol < nCols; IdxCol++) { SparseColumnVectors[IdxCol] = new SparseColumnVector(SourceSparseMatrix.SparseColumnVectors[IdxCol]); } flag_SameSparsePatterForAllColumns = SourceSparseMatrix.flag_SameSparsePatterForAllColumns; if (flag_SameSparsePatterForAllColumns) { SparsePatternOfEachColumn = new int[nRows]; Array.Copy(SourceSparseMatrix.SparsePatternOfEachColumn, SparsePatternOfEachColumn, nRows); } }
public static void HorizontalSumMatrix(DenseColumnVector z, SparseMatrix X) { if (z.Dim != X.nRows) { throw new Exception("Dimension mismatch."); } Array.Clear(z.VectorValue, 0, z.VectorValue.Length); for (int IdxCol = 0; IdxCol < X.nCols; IdxCol++) { int nNonzero = X.SparseColumnVectors[IdxCol].nNonzero; var xKey = X.SparseColumnVectors[IdxCol].Key; var xVal = X.SparseColumnVectors[IdxCol].Val; var zVal = z.VectorValue; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[xKey[IdxRow]] += xVal[IdxRow]; } } }
/* * z = mean(X,2): horizontal mean */ public static DenseColumnVector HorizontalMeanMatrix(SparseMatrix X) { DenseColumnVector z = HorizontalSumMatrix(X); return z; }
public static void VerticalSumMatrix(DenseRowVector z, SparseMatrix X) { Array.Clear(z.VectorValue, 0, z.VectorValue.Length); Parallel.For(0, X.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var zVal = z.VectorValue; var xVal = X.SparseColumnVectors[IdxCol].Val; int nNonzero = X.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxCol] += xVal[IdxRow]; } }); }
public static DenseColumnVector HorizontalSumMatrix(SparseMatrix X) { DenseColumnVector z = new DenseColumnVector(X.nRows); Array.Clear(z.VectorValue, 0, z.VectorValue.Length); for (int IdxCol = 0; IdxCol < X.nCols; IdxCol++ ) { int nNonzero = X.SparseColumnVectors[IdxCol].nNonzero; var xKey = X.SparseColumnVectors[IdxCol].Key; var xVal = X.SparseColumnVectors[IdxCol].Val; var zVal = z.VectorValue; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[xKey[IdxRow]] += xVal[IdxRow]; } } return z; }
/* * Z = X + Y */ public static void MatrixAddMatrix(DenseMatrix Z, DenseMatrix X, SparseMatrix Y) { // Check dimension if (Z.nRows != X.nRows || Z.nCols != X.nCols || Z.nRows != Y.nRows || Z.nCols != Y.nCols) { throw new Exception("Dimension mismatch."); } // Computation Parallel.For(0, Z.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { Array.Copy(X.DenseMatrixValue[IdxCol].VectorValue, Z.DenseMatrixValue[IdxCol].VectorValue, Z.DenseMatrixValue[IdxCol].VectorValue.Length); }); MatrixAddMatrix(Z, Y); }
public static void MatrixAddMatrix(SparseMatrix Z, SparseMatrix X) { // Check dimension if (Z.nRows != X.nRows || Z.nCols != X.nCols) { throw new Exception("Dimension mismatch."); } // Computation Parallel.For(0, Z.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var nNonzero = Z.SparseColumnVectors[IdxCol].nNonzero; var zVal = Z.SparseColumnVectors[IdxCol].Val; var xVal = X.SparseColumnVectors[IdxCol].Val; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxRow] += xVal[IdxRow]; } }); }
/* * Z = X + y (scalar) */ public static void ScalarAddMatrix(SparseMatrix Z, SparseMatrix X, float y) { // Dimension check if (Z.nCols != X.nCols || Z.nRows != X.nRows) { throw new Exception("Matrix dimension mismatch."); } // Computation Parallel.For(0, X.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var zVal = Z.SparseColumnVectors[IdxCol].Val; var xVal = X.SparseColumnVectors[IdxCol].Val; int nNonzero = X.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { //if (Z.SparseColumnVectors[IdxCol].Key[IdxRow] != X.SparseColumnVectors[IdxCol].Key[IdxRow]) //{ // throw new Exception("Sparse patterns do not match."); //} zVal[IdxRow] = xVal[IdxRow] + y; } }); }
public static void Exp(SparseMatrix Z) { int nCols = Z.nCols; int nRows = Z.nRows; Parallel.For(0, nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var zVal = Z.SparseColumnVectors[IdxCol].Val; int nNz = Z.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNz; ++IdxRow) { zVal[IdxRow] = (float)Math.Exp(zVal[IdxRow]); } }); }
public static void bsxfunVectorMultiplyMatrix(SparseMatrix X, DenseRowVector y) { if (X.nCols != y.Dim) { throw new Exception("Dimension mismatch."); } Parallel.For(0, X.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var xVal = X.SparseColumnVectors[IdxCol].Val; var yVal = y.VectorValue[IdxCol]; var nNonzero = X.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { xVal[IdxRow] *= yVal; } }); }
/* * Z = X^T * Y * Matrix transpose mulplication */ public static void MatrixTransposeMultiplyMatrix(DenseMatrix Z,DenseMatrix X, SparseMatrix Y) { // Dimension check if (X.nRows != Y.nRows || Z.nRows != X.nCols || Z.nCols != Y.nCols) { throw new Exception("Dimension mismatch."); } // Computation int total = Z.nCols * Z.nRows; int process_len = (total + THREADNUM - 1) / THREADNUM; Parallel.For(0, THREADNUM, new ParallelOptions{ MaxDegreeOfParallelism = MaxMultiThreadDegree}, thread_idx => { for (int t = 0; t < process_len; t++) { int id = thread_idx * process_len + t; if (id < total) { int IdxCol = id / Z.nRows; int IdxRow = id % Z.nRows; DenseColumnVector z = Z.DenseMatrixValue[IdxCol]; var x = X.DenseMatrixValue[IdxRow].VectorValue; SparseColumnVector y = Y.SparseColumnVectors[IdxCol]; var nNonzero = y.nNonzero; float sum = 0; var yKey = y.Key; var yVal = y.Val; for (int Idx = 0; Idx < nNonzero; ++ Idx) { sum += x[yKey[Idx]] * yVal[Idx]; } z.VectorValue[IdxRow] = sum; } else break; } }); }
/* * Z = bsxfun(@times, X, y) or Z = X * y, where y is a dense row or column vector */ public static void bsxfunVectorMultiplyMatrix(SparseMatrix Z, SparseMatrix X, DenseRowVector y) { if (Z.nCols != X.nCols || Z.nRows != X.nRows || Z.nCols != y.Dim) { throw new Exception("Dimension mismatch!"); } int ZnCols = Z.nCols; Parallel.For(0, ZnCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { int nNz = Z.SparseColumnVectors[IdxCol].nNonzero; var ZVal = Z.SparseColumnVectors[IdxCol].Val; var XVal = X.SparseColumnVectors[IdxCol].Val; var yVal = y.VectorValue; for (int IdxRow = 0; IdxRow < nNz; ++IdxRow) { ZVal[IdxRow] = XVal[IdxRow] * yVal[IdxCol]; } }); }
public static void ProjCols2OrthogonalSimplexPlane(SparseMatrix Z, SparseMatrix X) { if (Z.nCols != X.nCols || Z.nRows != X.nRows) { throw new Exception("Dimension mismatch."); } DenseRowVector TmpDenseRowVec = new DenseRowVector(X.nCols); MatrixOperation.VerticalSumMatrix(TmpDenseRowVec, X); MatrixOperation.ScalarMultiplyVector(TmpDenseRowVec, 1.0f / ((float)X.nRows)); MatrixOperation.bsxfunMatrixSubtractVector(Z, X, TmpDenseRowVec); }
public static void bsxfunMatrixSubtractVector(SparseMatrix Z, SparseMatrix X, DenseRowVector y) { if (Z.nCols != X.nCols || Z.nRows != X.nRows || Z.nCols != y.Dim) { throw new Exception("Dimension mismatch."); } int total = Z.nCols; int process_len = (total + THREADNUM - 1) / THREADNUM; Parallel.For(0, THREADNUM, new ParallelOptions{ MaxDegreeOfParallelism = MaxMultiThreadDegree}, thread_idx => { for (int t = 0; t < process_len; t++) { int IdxCol = thread_idx * process_len + t; if (IdxCol < total) { var zVal = Z.SparseColumnVectors[IdxCol].Val; var xVal = X.SparseColumnVectors[IdxCol].Val; var yVal = y.VectorValue[IdxCol]; int nNonzero = Z.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxRow] = xVal[IdxRow] - yVal; } } } }); }
public SparseMatrix GetColumns(int[] IdxColumns) { SparseMatrix SubMatrix = new SparseMatrix(nRows, IdxColumns.Length); if (SubMatrix.nCols != IdxColumns.Length) { throw new Exception("Number of desired columns is not equal to the target SubMatrix!"); } for (int IdxCol = 0; IdxCol < IdxColumns.Length; IdxCol++) { Array.Copy(SparseColumnVectors, IdxColumns[IdxCol], SubMatrix.SparseColumnVectors, IdxCol, 1); } return SubMatrix; }
/* * Z = X*Y, where X and Y are dense. * Only nonzero positions of Z will be computed if Z is sparse. */ public static void MatrixMultiplyMatrix(SparseMatrix Z, DenseMatrix X, DenseMatrix Y) { // Dimension check if (Z.nRows != X.nRows || Z.nCols != Y.nCols || X.nCols != Y.nRows) { throw new Exception("Matrix dimension mismatch in multiplication."); } int total = Z.nCols ; int process_len = (total + THREADNUM - 1) / THREADNUM; Parallel.For(0, THREADNUM, new ParallelOptions{ MaxDegreeOfParallelism = MaxMultiThreadDegree}, thread_idx => { for (int t = 0; t < process_len; t++) { int IdxCol = thread_idx * process_len + t; if (IdxCol < total) { var yVector = Y.DenseMatrixValue[IdxCol].VectorValue; SparseColumnVector z = Z.SparseColumnVectors[IdxCol]; var zVal = z.Val; var zKey = z.Key; int nNonzero = z.nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxRow] = 0; } for (int Idx = 0; Idx < X.nCols; ++ Idx) { // Compute the (IdxTrueRow, IdxCol)-th entry of Z, stored at (IdxRow, IdxCol) var xVector = X.DenseMatrixValue[Idx].VectorValue; var y = yVector[Idx]; for (int IdxRow = 0; IdxRow < nNonzero; ++ IdxRow) { // Get the actual row index of Z zVal[IdxRow] += xVector[zKey[IdxRow]] * y; } } } else break; } }); }
/* * Z = X.*Y */ public static void ElementwiseMatrixMultiplyMatrix(SparseMatrix Z, SparseMatrix X, SparseMatrix Y) { // Dimension check if (X.nCols != Y.nCols || X.nRows != Y.nRows || Z.nCols != X.nCols || Z.nRows != X.nRows) { throw new Exception("Dimension mismatch during elementwise matrix multiplication."); } // Elementwise matrix multiplication for (int IdxCol = 0; IdxCol < Z.nCols; IdxCol++) { for (int IdxRow = 0; IdxRow < Z.SparseColumnVectors[IdxCol].nNonzero; IdxRow++) { if (Z.SparseColumnVectors[IdxCol].Key[IdxRow] != X.SparseColumnVectors[IdxCol].Key[IdxRow] || Z.SparseColumnVectors[IdxCol].Key[IdxRow] != Y.SparseColumnVectors[IdxCol].Key[IdxRow]) { throw new Exception("Sparse patterns do not match in elementwise matrix multiplication."); } Z.SparseColumnVectors[IdxCol].Val[IdxRow] = X.SparseColumnVectors[IdxCol].Val[IdxRow] * Y.SparseColumnVectors[IdxCol].Val[IdxRow]; } } }
/* * Z = X * Y^T if IsCumSum == false * Z += X * Y^T is IsCumSum == true */ public static void MatrixMultiplyMatrixTranspose(DenseMatrix Z, SparseMatrix X, DenseMatrix Y, bool IsCumSum) { if (Z.nRows != X.nRows || Z.nCols != Y.nRows || X.nCols != Y.nCols) { throw new Exception("Dimension mismatch."); } int total = Z.nCols; int process_len = (total + THREADNUM - 1) / THREADNUM; Parallel.For(0, THREADNUM, new ParallelOptions{ MaxDegreeOfParallelism = MaxMultiThreadDegree}, thread_idx => { for (int t = 0; t < process_len; t++) { int IdxCol = thread_idx * process_len + t; if (IdxCol < total) { DenseColumnVector z = Z.DenseMatrixValue[IdxCol]; if (!IsCumSum) Array.Clear(z.VectorValue, 0, Z.nRows); for (int Idx = 0; Idx < X.nCols; Idx++) { SparseColumnVector x = X.SparseColumnVectors[Idx]; float yvalue = Y.DenseMatrixValue[Idx].VectorValue[IdxCol]; for (int IdxRow = 0; IdxRow < x.nNonzero; IdxRow++) { z.VectorValue[x.Key[IdxRow]] += x.Val[IdxRow] * yvalue; } } } else break; } }); }
public static void ElementwiseMatrixMultiplyMatrix(DenseMatrix Z, SparseMatrix X) { if (Z.nCols != X.nCols || Z.nRows != X.nRows) { throw new Exception("Dimension mismatch."); } Parallel.For(0, Z.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { int nNz = X.SparseColumnVectors[IdxCol].nNonzero; var xKey = X.SparseColumnVectors[IdxCol].Key; var xVal = X.SparseColumnVectors[IdxCol].Val; var zVal = Z.DenseMatrixValue[IdxCol].VectorValue; for (int IdxRow = 0; IdxRow < nNz; ++IdxRow) { zVal[xKey[IdxRow]] *= xVal[IdxRow]; } } ); }
public static void MatrixMultiplyMatrixTranspose(SparseMatrix Z, SparseMatrix X, DenseMatrix Y, bool IsCumSum) { if (Z.nRows != X.nRows || Z.nCols != Y.nRows || X.nCols != Y.nCols) { throw new Exception("Dimension mismatch."); } int total = Z.nCols; int process_len = (total + THREADNUM - 1) / THREADNUM; Parallel.For(0, THREADNUM, new ParallelOptions{ MaxDegreeOfParallelism = MaxMultiThreadDegree}, thread_idx => { var ZSparsePatternOfEachColumn = Z.SparsePatternOfEachColumn; var xnCols = X.nCols; for (int t = 0; t < process_len; ++t) { int IdxCol = thread_idx * process_len + t; if (IdxCol < total) { SparseColumnVector z = Z.SparseColumnVectors[IdxCol]; var zVal = z.Val; if (!IsCumSum) Array.Clear(zVal, 0, z.nNonzero); for (int Idx = 0; Idx < xnCols; ++Idx) { float yvalue = Y.DenseMatrixValue[Idx].VectorValue[IdxCol]; var xKey = X.SparseColumnVectors[Idx].Key; var xVal = X.SparseColumnVectors[Idx].Val; var xnNonzero = X.SparseColumnVectors[Idx].nNonzero; for (int IdxRow = 0; IdxRow < xnNonzero; ++IdxRow) { int xkey = xKey[IdxRow]; float xvalue = xVal[IdxRow]; zVal[ZSparsePatternOfEachColumn[xkey]] += xvalue * yvalue; } } } else break; } }); }
/* * Z = X ./ Y * Elementwise division */ public static void ElementwiseMatrixDivideMatrix(SparseMatrix Z, SparseMatrix X, SparseMatrix Y) { // Dimension check if (Z.nCols != X.nCols || Z.nRows != X.nRows || Z.nCols != Y.nCols || Z.nRows != Y.nRows) { throw new Exception("Dimension mismatch."); } // Computation int nCols = Z.nCols; Parallel.For(0, nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { var zVal = Z.SparseColumnVectors[IdxCol].Val; var xVal = X.SparseColumnVectors[IdxCol].Val; var yVal = Y.SparseColumnVectors[IdxCol].Val; int nNonzero = Z.SparseColumnVectors[IdxCol].nNonzero; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxRow] = xVal[IdxRow] / (yVal[IdxRow]+1e-12f); } }); }
/* * Z += a * x * y^T : Atomic add & thread safe, where x and y are column vectors, and a is a scalar. */ public static void AtomicAddVectorMultiplyVectorTranspose(SparseMatrix Z, SparseColumnVector x, DenseColumnVector y, float a) { if (Z.nRows != x.Dim || Z.nCols != y.Dim) { throw new Exception("Dimension mismatch."); } float product = 0.0f; float InitVal = 0.0f; float ComputedVal = 0.0f; int ZnCols = Z.nCols; int xNz = x.nNonzero; var xVal = x.Val; var xKey = x.Key; var yVal = y.VectorValue; var ZSparseColumnPattern = Z.SparsePatternOfEachColumn; for (int IdxCol = 0; IdxCol < ZnCols; ++IdxCol) { var ZVal = Z.SparseColumnVectors[IdxCol].Val; for (int IdxRow = 0; IdxRow < xNz; ++IdxRow) { product = xVal[IdxRow] * yVal[IdxCol] * a; int ZIdx = ZSparseColumnPattern[xKey[IdxRow]]; do { InitVal = ZVal[ZIdx]; ComputedVal = InitVal + product; } while (InitVal != Interlocked.CompareExchange(ref ZVal[ZIdx], ComputedVal, InitVal)); } } }
public static void MatrixSubtractMatrix(SparseMatrix Z, SparseMatrix Y) { if (Z.nRows != Y.nRows || Z.nCols != Y.nCols) { throw new Exception("Dimension mismatch."); } Parallel.For(0, Z.nCols, new ParallelOptions { MaxDegreeOfParallelism = MaxMultiThreadDegree }, IdxCol => { int nNonzero = Y.SparseColumnVectors[IdxCol].nNonzero; var zVal = Z.SparseColumnVectors[IdxCol].Val; var yVal = Y.SparseColumnVectors[IdxCol].Val; for (int IdxRow = 0; IdxRow < nNonzero; ++IdxRow) { zVal[IdxRow] -= yVal[IdxRow]; } }); }
public static float ComputeSupervisedLoss(SparseMatrix Dt, SparseMatrix y, string OutputType) { if (Dt.nCols != y.nCols || Dt.nRows != y.nRows) { throw new Exception("The numbers of samples from label and prediction do not match."); } SparseMatrix SparseMat = new SparseMatrix(y); SparseMatrix TmpSparseMat = new SparseMatrix(Dt); DenseRowVector TmpDenseRowVec = new DenseRowVector(Dt.nCols); float TrainingLoss = 0.0f; switch (OutputType) { case "softmaxCE": MatrixOperation.ScalarAddMatrix(SparseMat, y, 1e-20f); MatrixOperation.Log(SparseMat); MatrixOperation.ElementwiseMatrixMultiplyMatrix(TmpSparseMat, Dt, SparseMat); MatrixOperation.VerticalSumMatrix(TmpDenseRowVec, TmpSparseMat); TrainingLoss = TmpDenseRowVec.Sum() * (-1.0f); break; case "linearQuad": MatrixOperation.MatrixSubtractMatrix(SparseMat, Dt); MatrixOperation.ElementwiseSquare(SparseMat); MatrixOperation.VerticalSumMatrix(TmpDenseRowVec, SparseMat); TrainingLoss = TmpDenseRowVec.Sum(); break; case "linearCE": MatrixOperation.ScalarAddMatrix(SparseMat, y, 1e-20f); MatrixOperation.Log(SparseMat); MatrixOperation.ElementwiseMatrixMultiplyMatrix(TmpSparseMat, Dt, SparseMat); MatrixOperation.VerticalSumMatrix(TmpDenseRowVec, TmpSparseMat); TrainingLoss = TmpDenseRowVec.Sum() * (-1.0f); break; default: throw new Exception("Unknown OutputType."); } return TrainingLoss; }