|
|
@ -10,9 +10,11 @@ |
|
|
|
#include "src/exceptions/invalid_argument.h" |
|
|
|
#include "src/exceptions/out_of_range.h" |
|
|
|
#include "src/exceptions/file_IO_exception.h" |
|
|
|
#include "src/storage/BitVector.h" |
|
|
|
|
|
|
|
#include "src/misc/const_templates.h" |
|
|
|
#include "Eigen/Sparse" |
|
|
|
#include "gmm/gmm_matrix.h" |
|
|
|
|
|
|
|
#include "log4cplus/logger.h" |
|
|
|
#include "log4cplus/loggingmacros.h" |
|
|
@ -471,7 +473,7 @@ public: |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to convert a matrix that is not in a readable state to an Eigen matrix."); |
|
|
|
throw mrmc::exceptions::invalid_state("Trying to convert a matrix that is not in a readable state to an Eigen matrix."); |
|
|
|
} else { |
|
|
|
// Create a |
|
|
|
// Create the resulting matrix. |
|
|
|
int_fast32_t eigenRows = static_cast<int_fast32_t>(rowCount); |
|
|
|
Eigen::SparseMatrix<T, Eigen::RowMajor, int_fast32_t>* mat = new Eigen::SparseMatrix<T, Eigen::RowMajor, int_fast32_t>(eigenRows, eigenRows); |
|
|
|
|
|
|
@ -488,6 +490,7 @@ public: |
|
|
|
// than an average row, the other solution might be faster. |
|
|
|
// The desired conversion method may be set by an appropriate define. |
|
|
|
|
|
|
|
#define MRMC_USE_TRIPLETCONVERT |
|
|
|
# ifdef MRMC_USE_TRIPLETCONVERT |
|
|
|
|
|
|
|
// FIXME: Wouldn't it be more efficient to add the elements in |
|
|
@ -503,10 +506,12 @@ public: |
|
|
|
// and add the corresponding triplet. |
|
|
|
uint_fast64_t rowStart; |
|
|
|
uint_fast64_t rowEnd; |
|
|
|
uint_fast64_t zeroCount = 0; |
|
|
|
for (uint_fast64_t row = 0; row <= rowCount; ++row) { |
|
|
|
rowStart = rowIndications[row]; |
|
|
|
rowEnd = rowIndications[row + 1]; |
|
|
|
while (rowStart < rowEnd) { |
|
|
|
if (valueStorage[rowStart] == 0) zeroCount++; |
|
|
|
tripletList.push_back(IntTriplet(row, columnIndications[rowStart], valueStorage[rowStart])); |
|
|
|
++rowStart; |
|
|
|
} |
|
|
@ -514,7 +519,8 @@ public: |
|
|
|
|
|
|
|
// Then add the elements on the diagonal. |
|
|
|
for (uint_fast64_t i = 0; i <= rowCount; ++i) { |
|
|
|
tripletList.push_back(IntTriplet(i, i, diagonalStorage[i])); |
|
|
|
if (diagonalStorage[i] == 0) zeroCount++; |
|
|
|
// tripletList.push_back(IntTriplet(i, i, diagonalStorage[i])); |
|
|
|
} |
|
|
|
|
|
|
|
// Let Eigen create a matrix from the given list of triplets. |
|
|
@ -530,16 +536,19 @@ public: |
|
|
|
// them to the matrix individually. |
|
|
|
uint_fast64_t rowStart; |
|
|
|
uint_fast64_t rowEnd; |
|
|
|
uint_fast64_t count = 0; |
|
|
|
for (uint_fast64_t row = 0; row < rowCount; ++row) { |
|
|
|
rowStart = rowIndications[row]; |
|
|
|
rowEnd = rowIndications[row + 1]; |
|
|
|
|
|
|
|
// Insert the element on the diagonal. |
|
|
|
mat->insert(row, row) = diagonalStorage[row]; |
|
|
|
count++; |
|
|
|
|
|
|
|
// Insert the elements that are not on the diagonal |
|
|
|
while (rowStart < rowEnd) { |
|
|
|
mat->insert(row, columnIndications[rowStart]) = valueStorage[rowStart]; |
|
|
|
count++; |
|
|
|
++rowStart; |
|
|
|
} |
|
|
|
} |
|
|
@ -556,6 +565,57 @@ public: |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Converts the matrix into a sparse matrix in the GMMXX format. |
|
|
|
* @return A pointer to a column-major sparse matrix in GMMXX format. |
|
|
|
*/ |
|
|
|
gmm::csr_matrix<T>* toGMMXXSparseMatrix() { |
|
|
|
// Prepare the resulting matrix. |
|
|
|
gmm::csr_matrix<T>* result = new gmm::csr_matrix<T>(rowCount, rowCount); |
|
|
|
|
|
|
|
LOG4CPLUS_INFO(logger, "Starting copy1."); |
|
|
|
// Copy over the row indications as GMMXX uses the very same internal format. |
|
|
|
result->jc.reserve(rowCount + 1); |
|
|
|
std::copy(rowIndications, rowIndications + (rowCount + 1), result->jc.begin()); |
|
|
|
LOG4CPLUS_INFO(logger, "Done copy1."); |
|
|
|
|
|
|
|
// For the column indications and the actual values, we have to gather |
|
|
|
// the values in a temporary array first, as we have to integrate |
|
|
|
// the values from the diagonal. |
|
|
|
uint_fast64_t realNonZeros = getNonZeroEntryCount() + getDiagonalNonZeroEntryCount(); |
|
|
|
uint_fast64_t* tmpColumnIndicationsArray = new uint_fast64_t[realNonZeros]; |
|
|
|
uint_fast64_t* tmpValueArray = new uint_fast64_t[realNonZeros]; |
|
|
|
T zero(0); |
|
|
|
uint_fast64_t currentPosition = 0; |
|
|
|
for (uint_fast64_t i = 0; i < rowCount; ++i) { |
|
|
|
bool includedDiagonal = false; |
|
|
|
for (uint_fast64_t j = rowIndications[i]; j < rowIndications[i + 1]; ++j) { |
|
|
|
if (diagonalStorage[i] != zero && !includedDiagonal && columnIndications[j] > i) { |
|
|
|
includedDiagonal = true; |
|
|
|
tmpColumnIndicationsArray[currentPosition] = i; |
|
|
|
tmpValueArray[currentPosition] = diagonalStorage[i]; |
|
|
|
++currentPosition; |
|
|
|
} |
|
|
|
tmpColumnIndicationsArray[currentPosition] = columnIndications[j]; |
|
|
|
tmpValueArray[currentPosition] = valueStorage[j]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
LOG4CPLUS_INFO(logger, "Starting copy2."); |
|
|
|
// Now, we can copy the temporary array to the GMMXX format. |
|
|
|
result->ir.reserve(realNonZeros); |
|
|
|
std::copy(tmpColumnIndicationsArray, tmpColumnIndicationsArray + realNonZeros, result->ir.begin()); |
|
|
|
delete[] tmpColumnIndicationsArray; |
|
|
|
|
|
|
|
// And do the same thing with the actual values. |
|
|
|
result->pr.resize(realNonZeros); |
|
|
|
std::copy(tmpValueArray, tmpValueArray + realNonZeros, result->pr.begin()); |
|
|
|
delete[] tmpValueArray; |
|
|
|
LOG4CPLUS_INFO(logger, "Done copy2."); |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns the number of non-zero entries that are not on the diagonal. |
|
|
|
* @returns The number of non-zero entries that are not on the diagonal. |
|
|
@ -564,6 +624,19 @@ public: |
|
|
|
return nonZeroEntryCount; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns the number of non-zero entries on the diagonal. |
|
|
|
* @return The number of non-zero entries on the diagonal. |
|
|
|
*/ |
|
|
|
uint_fast64_t getDiagonalNonZeroEntryCount() const { |
|
|
|
uint_fast64_t result = 0; |
|
|
|
T zero(0); |
|
|
|
for (uint_fast64_t i = 0; i < rowCount; ++i) { |
|
|
|
if (diagonalStorage[i] != zero) ++result; |
|
|
|
} |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* This function makes the given row absorbing. This means that all |
|
|
|
* entries in will be set to 0 and the value 1 will be written |
|
|
@ -594,6 +667,104 @@ public: |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
* Computes the sum of the elements in the given row whose column bits |
|
|
|
* are set to one on the given constraint. |
|
|
|
* @param row The row whose elements to add. |
|
|
|
* @param constraint A bit vector that indicates which columns to add. |
|
|
|
* @return The sum of the elements in the given row whose column bits |
|
|
|
* are set to one on the given constraint. |
|
|
|
*/ |
|
|
|
T getConstrainedRowSum(const uint_fast64_t row, const mrmc::storage::BitVector& constraint) { |
|
|
|
T result(0); |
|
|
|
for (uint_fast64_t i = rowIndications[row]; i < rowIndications[row + 1]; ++i) { |
|
|
|
if (constraint.get(columnIndications[i])) { |
|
|
|
result += valueStorage[i]; |
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Computes a vector in which each element is the sum of those elements in the |
|
|
|
* corresponding row whose column bits are set to one in the given constraint. |
|
|
|
* @param constraint A bit vector that indicates which columns to add. |
|
|
|
* @param resultVector A pointer to the resulting vector that has at least |
|
|
|
* as many elements as there are bits set to true in the constraint. |
|
|
|
*/ |
|
|
|
void getConstrainedRowCountVector(const mrmc::storage::BitVector& constraint, T* resultVector) { |
|
|
|
for (uint_fast64_t row = 0; row < rowCount; ++row) { |
|
|
|
resultVector[row] = getConstrainedRowSum(row, constraint); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Creates a sub-matrix of the current matrix by dropping all rows and |
|
|
|
* columns whose bits are not set to one in the given bit vector. |
|
|
|
* @param constraint A bit vector indicating which rows and columns to drop. |
|
|
|
* @return A pointer to a sparse matrix that is a sub-matrix of the current one. |
|
|
|
*/ |
|
|
|
SquareSparseMatrix* getSubmatrix(mrmc::storage::BitVector& constraint) { |
|
|
|
LOG4CPLUS_DEBUG(logger, "Creating a sub-matrix with " << constraint.getNumberOfSetBits() << " rows."); |
|
|
|
|
|
|
|
// Check for valid constraint. |
|
|
|
if (constraint.getNumberOfSetBits() == 0) { |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to create a sub-matrix of size 0."); |
|
|
|
throw mrmc::exceptions::invalid_argument("Trying to create a sub-matrix of size 0."); |
|
|
|
} |
|
|
|
|
|
|
|
// First, we need to determine the number of non-zero entries of the |
|
|
|
// sub-matrix. |
|
|
|
uint_fast64_t subNonZeroEntries = 0; |
|
|
|
for (auto rowIndex : constraint) { |
|
|
|
for (uint_fast64_t i = rowIndications[rowIndex]; i < rowIndications[rowIndex + 1]; ++i) { |
|
|
|
if (constraint.get(columnIndications[i])) { |
|
|
|
++subNonZeroEntries; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
LOG4CPLUS_DEBUG(logger, "Done counting non-zeros."); |
|
|
|
|
|
|
|
// Create and initialize resulting matrix. |
|
|
|
SquareSparseMatrix* result = new SquareSparseMatrix(constraint.getNumberOfSetBits()); |
|
|
|
result->initialize(subNonZeroEntries); |
|
|
|
|
|
|
|
// Create a temporary array that stores for each index whose bit is set |
|
|
|
// to true the number of bits that were set before that particular index. |
|
|
|
uint_fast64_t* bitsSetBeforeIndex = new uint_fast64_t[rowCount]; |
|
|
|
uint_fast64_t lastIndex = 0; |
|
|
|
uint_fast64_t currentNumberOfSetBits = 0; |
|
|
|
for (auto index : constraint) { |
|
|
|
while (lastIndex <= index) { |
|
|
|
bitsSetBeforeIndex[lastIndex++] = currentNumberOfSetBits; |
|
|
|
} |
|
|
|
++currentNumberOfSetBits; |
|
|
|
} |
|
|
|
|
|
|
|
// Copy over selected entries. |
|
|
|
uint_fast64_t rowCount = 0; |
|
|
|
for (auto rowIndex : constraint) { |
|
|
|
result->addNextValue(rowCount, rowCount, diagonalStorage[rowIndex]); |
|
|
|
|
|
|
|
for (uint_fast64_t i = rowIndications[rowIndex]; i < rowIndications[rowIndex + 1]; ++i) { |
|
|
|
if (constraint.get(columnIndications[i])) { |
|
|
|
result->addNextValue(rowCount, bitsSetBeforeIndex[columnIndications[i]], valueStorage[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
++rowCount; |
|
|
|
} |
|
|
|
|
|
|
|
// Dispose of the temporary array. |
|
|
|
delete[] bitsSetBeforeIndex; |
|
|
|
|
|
|
|
// Finalize sub-matrix and return result. |
|
|
|
result->finalize(); |
|
|
|
LOG4CPLUS_DEBUG(logger, "Done creating sub-matrix."); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns the size of the matrix in memory measured in bytes. |
|
|
|
* @return The size of the matrix in memory measured in bytes. |
|
|
|