/// <summary> /// Initializes the preconditioner and loads the internal data structures. /// </summary> /// <param name="matrix"> /// The <see cref="Matrix"/> upon which this preconditioner is based. Note that the /// method takes a general matrix type. However internally the data is stored /// as a sparse matrix. Therefore it is not recommended to pass a dense matrix. /// </param> /// <exception cref="ArgumentNullException"> If <paramref name="matrix"/> is <see langword="null" />.</exception> /// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception> public void Initialize(Matrix matrix) { if (matrix == null) { throw new ArgumentNullException("matrix"); } if (matrix.RowCount != matrix.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); } var sparseMatrix = (matrix is SparseMatrix) ? matrix as SparseMatrix : SparseMatrix.OfMatrix(matrix); // The creation of the preconditioner follows the following algorithm. // spaceLeft = lfilNnz * nnz(A) // for i = 1, .. , n // { // w = a(i,*) // for j = 1, .. , i - 1 // { // if (w(j) != 0) // { // w(j) = w(j) / a(j,j) // if (w(j) < dropTol) // { // w(j) = 0; // } // if (w(j) != 0) // { // w = w - w(j) * U(j,*) // } // } // } // // for j = i, .. ,n // { // if w(j) <= dropTol * ||A(i,*)|| // { // w(j) = 0 // } // } // // spaceRow = spaceLeft / (n - i + 1) // Determine the space for this row // lfil = spaceRow / 2 // space for this row of L // l(i,j) = w(j) for j = 1, .. , i -1 // only the largest lfil elements // // lfil = spaceRow - nnz(L(i,:)) // space for this row of U // u(i,j) = w(j) for j = i, .. , n // only the largest lfil - 1 elements // w = 0 // // if max(U(i,i + 1: n)) > U(i,i) / pivTol then // pivot if necessary // { // pivot by swapping the max and the diagonal entries // Update L, U // Update P // } // spaceLeft = spaceLeft - nnz(L(i,:)) - nnz(U(i,:)) // } // Create the lower triangular matrix _lower = new SparseMatrix(sparseMatrix.RowCount); // Create the upper triangular matrix and copy the values _upper = new SparseMatrix(sparseMatrix.RowCount); // Create the pivot array _pivots = new int[sparseMatrix.RowCount]; for (var i = 0; i < _pivots.Length; i++) { _pivots[i] = i; } Vector workVector = new DenseVector(sparseMatrix.RowCount); Vector rowVector = new DenseVector(sparseMatrix.ColumnCount); var indexSorting = new int[sparseMatrix.RowCount]; // spaceLeft = lfilNnz * nnz(A) var spaceLeft = (int)_fillLevel * sparseMatrix.NonZerosCount; // for i = 1, .. , n for (var i = 0; i < sparseMatrix.RowCount; i++) { // w = a(i,*) sparseMatrix.Row(i, workVector); // pivot the row PivotRow(workVector); var vectorNorm = workVector.InfinityNorm(); // for j = 1, .. , i - 1) for (var j = 0; j < i; j++) { // if (w(j) != 0) // { // w(j) = w(j) / a(j,j) // if (w(j) < dropTol) // { // w(j) = 0; // } // if (w(j) != 0) // { // w = w - w(j) * U(j,*) // } if (workVector[j] != 0.0) { // Calculate the multiplication factors that go into the L matrix workVector[j] = workVector[j] / _upper[j, j]; if (Math.Abs(workVector[j]) < _dropTolerance) { workVector[j] = 0.0f; } // Calculate the addition factor if (workVector[j] != 0.0) { // vector update all in one go _upper.Row(j, rowVector); // zero out columnVector[k] because we don't need that // one anymore for k = 0 to k = j for (var k = 0; k <= j; k++) { rowVector[k] = 0.0f; } rowVector.Multiply(workVector[j], rowVector); workVector.Subtract(rowVector, workVector); } } } // for j = i, .. ,n for (var j = i; j < sparseMatrix.RowCount; j++) { // if w(j) <= dropTol * ||A(i,*)|| // { // w(j) = 0 // } if (Math.Abs(workVector[j]) <= _dropTolerance * vectorNorm) { workVector[j] = 0.0f; } } // spaceRow = spaceLeft / (n - i + 1) // Determine the space for this row var spaceRow = spaceLeft / (sparseMatrix.RowCount - i + 1); // lfil = spaceRow / 2 // space for this row of L var fillLevel = spaceRow / 2; FindLargestItems(0, i - 1, indexSorting, workVector); // l(i,j) = w(j) for j = 1, .. , i -1 // only the largest lfil elements var lowerNonZeroCount = 0; var count = 0; for (var j = 0; j < i; j++) { if ((count > fillLevel) || (indexSorting[j] == -1)) { break; } _lower[i, indexSorting[j]] = workVector[indexSorting[j]]; count += 1; lowerNonZeroCount += 1; } FindLargestItems(i + 1, sparseMatrix.RowCount - 1, indexSorting, workVector); // lfil = spaceRow - nnz(L(i,:)) // space for this row of U fillLevel = spaceRow - lowerNonZeroCount; // u(i,j) = w(j) for j = i + 1, .. , n // only the largest lfil - 1 elements var upperNonZeroCount = 0; count = 0; for (var j = 0; j < sparseMatrix.RowCount - i; j++) { if ((count > fillLevel - 1) || (indexSorting[j] == -1)) { break; } _upper[i, indexSorting[j]] = workVector[indexSorting[j]]; count += 1; upperNonZeroCount += 1; } // Simply copy the diagonal element. Next step is to see if we pivot _upper[i, i] = workVector[i]; // if max(U(i,i + 1: n)) > U(i,i) / pivTol then // pivot if necessary // { // pivot by swapping the max and the diagonal entries // Update L, U // Update P // } // Check if we really need to pivot. If (i+1) >=(mCoefficientMatrix.Rows -1) then // we are working on the last row. That means that there is only one number // And pivoting is useless. Also the indexSorting array will only contain // -1 values. if ((i + 1) < (sparseMatrix.RowCount - 1)) { if (Math.Abs(workVector[i]) < _pivotTolerance * Math.Abs(workVector[indexSorting[0]])) { // swap columns of u (which holds the values of A in the // sections that haven't been partitioned yet. SwapColumns(_upper, i, indexSorting[0]); // Update P var temp = _pivots[i]; _pivots[i] = _pivots[indexSorting[0]]; _pivots[indexSorting[0]] = temp; } } // spaceLeft = spaceLeft - nnz(L(i,:)) - nnz(U(i,:)) spaceLeft -= lowerNonZeroCount + upperNonZeroCount; } for (var i = 0; i < _lower.RowCount; i++) { _lower[i, i] = 1.0f; } }
/// <summary> /// Initializes the preconditioner and loads the internal data structures. /// </summary> /// <param name="matrix"> /// The <see cref="Matrix"/> upon which this preconditioner is based. Note that the /// method takes a general matrix type. However internally the data is stored /// as a sparse matrix. Therefore it is not recommended to pass a dense matrix. /// </param> /// <exception cref="ArgumentNullException"> If <paramref name="matrix"/> is <see langword="null" />.</exception> /// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception> public void Initialize(Matrix <float> matrix) { if (matrix == null) { throw new ArgumentNullException("matrix"); } if (matrix.RowCount != matrix.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); } SparseMatrix sparseMatrix = matrix as SparseMatrix ?? SparseMatrix.OfMatrix(matrix); // The creation of the preconditioner follows the following algorithm. // spaceLeft = lfilNnz * nnz(A) // for i = 1, .. , n // { // w = a(i,*) // for j = 1, .. , i - 1 // { // if (w(j) != 0) // { // w(j) = w(j) / a(j,j) // if (w(j) < dropTol) // { // w(j) = 0; // } // if (w(j) != 0) // { // w = w - w(j) * U(j,*) // } // } // } // // for j = i, .. ,n // { // if w(j) <= dropTol * ||A(i,*)|| // { // w(j) = 0 // } // } // // spaceRow = spaceLeft / (n - i + 1) // Determine the space for this row // lfil = spaceRow / 2 // space for this row of L // l(i,j) = w(j) for j = 1, .. , i -1 // only the largest lfil elements // // lfil = spaceRow - nnz(L(i,:)) // space for this row of U // u(i,j) = w(j) for j = i, .. , n // only the largest lfil - 1 elements // w = 0 // // if max(U(i,i + 1: n)) > U(i,i) / pivTol then // pivot if necessary // { // pivot by swapping the max and the diagonal entries // Update L, U // Update P // } // spaceLeft = spaceLeft - nnz(L(i,:)) - nnz(U(i,:)) // } // Create the lower triangular matrix _lower = new SparseMatrix(sparseMatrix.RowCount); // Create the upper triangular matrix and copy the values _upper = new SparseMatrix(sparseMatrix.RowCount); // Create the pivot array _pivots = new int[sparseMatrix.RowCount]; for (var i = 0; i < _pivots.Length; i++) { _pivots[i] = i; } var workVector = new DenseVector(sparseMatrix.RowCount); var rowVector = new DenseVector(sparseMatrix.ColumnCount); var indexSorting = new int[sparseMatrix.RowCount]; // spaceLeft = lfilNnz * nnz(A) var spaceLeft = (int)_fillLevel * sparseMatrix.NonZerosCount; // for i = 1, .. , n for (var i = 0; i < sparseMatrix.RowCount; i++) { // w = a(i,*) sparseMatrix.Row(i, workVector); // pivot the row PivotRow(workVector); var vectorNorm = workVector.InfinityNorm(); // for j = 1, .. , i - 1) for (var j = 0; j < i; j++) { // if (w(j) != 0) // { // w(j) = w(j) / a(j,j) // if (w(j) < dropTol) // { // w(j) = 0; // } // if (w(j) != 0) // { // w = w - w(j) * U(j,*) // } if (workVector[j] != 0.0) { // Calculate the multiplication factors that go into the L matrix workVector[j] = workVector[j] / _upper[j, j]; if (Math.Abs(workVector[j]) < _dropTolerance) { workVector[j] = 0.0f; } // Calculate the addition factor if (workVector[j] != 0.0) { // vector update all in one go _upper.Row(j, rowVector); // zero out columnVector[k] because we don't need that // one anymore for k = 0 to k = j for (var k = 0; k <= j; k++) { rowVector[k] = 0.0f; } rowVector.Multiply(workVector[j], rowVector); workVector.Subtract(rowVector, workVector); } } } // for j = i, .. ,n for (var j = i; j < sparseMatrix.RowCount; j++) { // if w(j) <= dropTol * ||A(i,*)|| // { // w(j) = 0 // } if (Math.Abs(workVector[j]) <= _dropTolerance * vectorNorm) { workVector[j] = 0.0f; } } // spaceRow = spaceLeft / (n - i + 1) // Determine the space for this row var spaceRow = spaceLeft / (sparseMatrix.RowCount - i + 1); // lfil = spaceRow / 2 // space for this row of L var fillLevel = spaceRow / 2; FindLargestItems(0, i - 1, indexSorting, workVector); // l(i,j) = w(j) for j = 1, .. , i -1 // only the largest lfil elements var lowerNonZeroCount = 0; var count = 0; for (var j = 0; j < i; j++) { if ((count > fillLevel) || (indexSorting[j] == -1)) { break; } _lower[i, indexSorting[j]] = workVector[indexSorting[j]]; count += 1; lowerNonZeroCount += 1; } FindLargestItems(i + 1, sparseMatrix.RowCount - 1, indexSorting, workVector); // lfil = spaceRow - nnz(L(i,:)) // space for this row of U fillLevel = spaceRow - lowerNonZeroCount; // u(i,j) = w(j) for j = i + 1, .. , n // only the largest lfil - 1 elements var upperNonZeroCount = 0; count = 0; for (var j = 0; j < sparseMatrix.RowCount - i; j++) { if ((count > fillLevel - 1) || (indexSorting[j] == -1)) { break; } _upper[i, indexSorting[j]] = workVector[indexSorting[j]]; count += 1; upperNonZeroCount += 1; } // Simply copy the diagonal element. Next step is to see if we pivot _upper[i, i] = workVector[i]; // if max(U(i,i + 1: n)) > U(i,i) / pivTol then // pivot if necessary // { // pivot by swapping the max and the diagonal entries // Update L, U // Update P // } // Check if we really need to pivot. If (i+1) >=(mCoefficientMatrix.Rows -1) then // we are working on the last row. That means that there is only one number // And pivoting is useless. Also the indexSorting array will only contain // -1 values. if ((i + 1) < (sparseMatrix.RowCount - 1)) { if (Math.Abs(workVector[i]) < _pivotTolerance * Math.Abs(workVector[indexSorting[0]])) { // swap columns of u (which holds the values of A in the // sections that haven't been partitioned yet. SwapColumns(_upper, i, indexSorting[0]); // Update P var temp = _pivots[i]; _pivots[i] = _pivots[indexSorting[0]]; _pivots[indexSorting[0]] = temp; } } // spaceLeft = spaceLeft - nnz(L(i,:)) - nnz(U(i,:)) spaceLeft -= lowerNonZeroCount + upperNonZeroCount; } for (var i = 0; i < _lower.RowCount; i++) { _lower[i, i] = 1.0f; } }