diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index e553e11..42440c0 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -1,6 +1,7 @@ name: Build and Deploy on: + pull_request: push: tags: - 'v*' @@ -20,6 +21,9 @@ jobs: - os: macos-latest platform: darwin arch: arm64 + - os: windows-latest + platform: win32 + arch: x64 steps: - uses: actions/checkout@v4 @@ -119,6 +123,7 @@ jobs: publish: name: Publish to npm needs: build + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest permissions: contents: read diff --git a/binding.gyp b/binding.gyp index b97b612..e9e50fc 100644 --- a/binding.gyp +++ b/binding.gyp @@ -56,17 +56,21 @@ }], ["OS=='win'", { + "include_dirs": [ + "C:/vcpkg/installed/x64-windows/include" + ], "libraries": [ "<(module_root_dir)/vendor/lib/networkit.lib", "<(module_root_dir)/vendor/lib/networkit/networkit_state.lib", "<(module_root_dir)/vendor/lib/tlx.lib", - "arrow.lib" + "C:/vcpkg/installed/x64-windows/lib/arrow.lib" ], "msvs_settings": { "VCCLCompilerTool": { "ExceptionHandling": 1, "RuntimeLibrary": 2, # 2 = /MD (MD_DynamicRelease), matching prebuilt networkit.lib - "AdditionalOptions": ["/std:c++20", "/openmp", "/W0"] + "RuntimeTypeInfo": "true", + "AdditionalOptions": ["/std:c++20", "/openmp", "/W0", "/MD", "/GR"] } } }] diff --git a/scripts/build-native.js b/scripts/build-native.js index 52036ed..0ef29a0 100644 --- a/scripts/build-native.js +++ b/scripts/build-native.js @@ -30,7 +30,28 @@ function useHomebrewLlvmIfAvailable(env) { return env; } -const args = ['node-gyp', 'rebuild', ...process.argv.slice(2)]; +function nodeGypCommand() { + try { + return { + command: process.execPath, + args: [require.resolve('node-gyp/bin/node-gyp.js'), 'rebuild', ...process.argv.slice(2)], + }; + } catch { + if (process.env.npm_execpath) { + return { + command: process.execPath, + args: [process.env.npm_execpath, 'exec', '--', 'node-gyp', 'rebuild', ...process.argv.slice(2)], + }; + } + + return { + command: process.platform === 'win32' ? 'npx.cmd' : 'npx', + args: ['node-gyp', 'rebuild', ...process.argv.slice(2)], + }; + } +} + +const { command, args } = nodeGypCommand(); const env = useHomebrewLlvmIfAvailable(process.env); if (process.platform === 'darwin') { @@ -43,7 +64,7 @@ if (process.platform === 'darwin') { } } -execFileSync('npm', ['exec', '--', ...args], { +execFileSync(command, args, { cwd: root, env, stdio: 'inherit', diff --git a/vendor/include/networkit/GlobalState.hpp b/vendor/include/networkit/GlobalState.hpp new file mode 100644 index 0000000..1dbd01f --- /dev/null +++ b/vendor/include/networkit/GlobalState.hpp @@ -0,0 +1,86 @@ + +#ifndef NETWORKIT_GLOBAL_STATE_HPP_ +#define NETWORKIT_GLOBAL_STATE_HPP_ + +#if defined(NETWORKIT_BUILDING_STATELIB) +#if defined(WIN32) +#define NETWORKIT_EXPORT __declspec(dllexport) +#else +#define NETWORKIT_EXPORT +#endif // WIN32 +#else +#if defined(WIN32) +#define NETWORKIT_EXPORT __declspec(dllimport) +#else +#define NETWORKIT_EXPORT +#endif // WIN32 +#endif // NETWORKIT_BUILDING_STATELIB + +#include +#include +#include +#include +#include + +#include +#include + +namespace NetworKit { + +namespace GlobalState { + +// Global states used for auxiliary/Random + +// The global seed generation functions as an epoch counter +// for each time, the seed was updated. At the same time it +// releases the changes made to the seed values to other +// threads which always access it by an aquire. +// seedValues and seedUseThreadId can hence be accesses +// relaxed. +// As long as globalSeedGeneration is zero, the getURNG() +// ignores these two variables. + +NETWORKIT_EXPORT uint64_t getSeed(); +NETWORKIT_EXPORT void setSeed(uint64_t seed); + +NETWORKIT_EXPORT uint64_t getGlobalSeed(); +NETWORKIT_EXPORT void incGlobalSeed(); + +NETWORKIT_EXPORT void setSeedUseThreadId(bool useThreadId); +NETWORKIT_EXPORT bool getSeedUseThreadId(); + +// Global states used for auxiliary/Log +NETWORKIT_EXPORT Aux::Log::LogLevel getLogLevel(); +NETWORKIT_EXPORT void setLogLevel(Aux::Log::LogLevel p = Aux::Log::LogLevel::INFO); + +NETWORKIT_EXPORT bool getPrintTime(); +NETWORKIT_EXPORT void setPrintTime(bool b); + +NETWORKIT_EXPORT bool getPrintLocation(); +NETWORKIT_EXPORT void setPrintLocation(bool b); + +NETWORKIT_EXPORT std::ofstream &getLogFile(); +NETWORKIT_EXPORT void setLogfile(std::string_view filename); + +NETWORKIT_EXPORT std::mutex &getLogFileMutex(); + +NETWORKIT_EXPORT bool getLogFileIsOpen(); + +// Global states used for auxiliary/SignalHandling +NETWORKIT_EXPORT bool getReceivedSIGINT(); +NETWORKIT_EXPORT void setReceivedSIGINT(bool isReceivedSIGINT); + +NETWORKIT_EXPORT bool getRootSet(); +NETWORKIT_EXPORT void setRootSet(bool isRootSet); + +NETWORKIT_EXPORT auto getPrevHandler() -> void (*)(int); +NETWORKIT_EXPORT void setPrevHandler(void (*handler)(int)); + +NETWORKIT_EXPORT Aux::SignalHandler *getRoot(); +NETWORKIT_EXPORT void setRoot(Aux::SignalHandler *rootHandler); + +} // namespace GlobalState + +} // namespace NetworKit + +#endif // NETWORKIT_GLOBAL_STATE_HPP_ diff --git a/vendor/include/networkit/Globals.hpp b/vendor/include/networkit/Globals.hpp new file mode 100644 index 0000000..c1fe98e --- /dev/null +++ b/vendor/include/networkit/Globals.hpp @@ -0,0 +1,41 @@ +/* + * Globals.hpp + * + * Created on: 06.02.2013 + * Author: Christian Staudt (christian.staudt@kit.edu) + */ + +#ifndef NETWORKIT_GLOBALS_HPP_ +#define NETWORKIT_GLOBALS_HPP_ + +#include +#include +#include + +namespace NetworKit { +using index = uint64_t; ///< more expressive name for an index into an array + +/// Should be used in OpenMP parallel for-loops and is associated with unsigned semantics. +/// On MSVC it falls back to being signed, as MSVC does not support unsigned parallel fors. +#ifdef _MSC_VER +using omp_index = int64_t; +#else +using omp_index = index; +#endif // _MSC_VER + +using coordinate = double; + +using count = uint64_t; ///< more expressive name for an integer quantity +using node = index; ///< node indices are 0-based +using edgeweight = double; ///< edge weight type +using edgeid = index; ///< edge id + +constexpr edgeweight defaultEdgeWeight = 1.0; +constexpr edgeweight nullWeight = 0.0; +constexpr index none = std::numeric_limits::max(); ///< value for not existing nodes/edges + +constexpr double PI = 3.141592653589793238462643383279502884197169399375105820974944592307816406286; + +} // namespace NetworKit + +#endif // NETWORKIT_GLOBALS_HPP_ diff --git a/vendor/include/networkit/algebraic/AlgebraicGlobals.hpp b/vendor/include/networkit/algebraic/AlgebraicGlobals.hpp new file mode 100644 index 0000000..9a8d51c --- /dev/null +++ b/vendor/include/networkit/algebraic/AlgebraicGlobals.hpp @@ -0,0 +1,27 @@ +/* + * AlgebraicGlobals.h + * + * Created on: May 31, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_ALGEBRAIC_GLOBALS_HPP_ +#define NETWORKIT_ALGEBRAIC_ALGEBRAIC_GLOBALS_HPP_ + +#include + +namespace NetworKit { + +/** Represents a matrix entry s.t. matrix(row, column) = value */ +struct Triplet { + index row; + index column; + double value; +}; + +/** Floating point epsilon to use in comparisons. */ +constexpr double FLOAT_EPSILON = 1e-9; + +} // namespace NetworKit + +#endif // NETWORKIT_ALGEBRAIC_ALGEBRAIC_GLOBALS_HPP_ diff --git a/vendor/include/networkit/algebraic/CSRGeneralMatrix.hpp b/vendor/include/networkit/algebraic/CSRGeneralMatrix.hpp new file mode 100644 index 0000000..f13090b --- /dev/null +++ b/vendor/include/networkit/algebraic/CSRGeneralMatrix.hpp @@ -0,0 +1,1292 @@ +/* + * CSRGeneralMatrix.hpp + * + * Created on: May 6, 2015 + * Authors: Michael Wegner + * Eugenio Angriman + */ + +#ifndef NETWORKIT_ALGEBRAIC_CSR_GENERAL_MATRIX_HPP_ +#define NETWORKIT_ALGEBRAIC_CSR_GENERAL_MATRIX_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * The CSRGeneralMatrix class represents a sparse matrix stored in CSR-Format + * (i.e. compressed sparse row). + * If speed is important, use this CSRGeneralMatrix instead of the Matrix class. + */ +template +class CSRGeneralMatrix { + std::vector rowIdx, columnIdx; + std::vector nonZeros; + + count nRows, nCols; + bool isSorted; + ValueType zero; + + class IndexProxy { + public: + IndexProxy(CSRGeneralMatrix &mat, index i, index j) : Matrix{mat}, i{i}, j{j} {} + + operator const ValueType &() const { + return const_cast(Matrix)(i, j); + } + + void operator=(double rhs) { Matrix.setValue(i, j, rhs); } + + private: + CSRGeneralMatrix &Matrix; + index i; + index j; + }; + +public: + /** Default constructor */ + CSRGeneralMatrix() + : rowIdx(0), columnIdx(0), nonZeros(0), nRows(0), nCols(0), isSorted(true), zero(0) {} + + /** + * Constructs the CSRGeneralMatrix with size @a dimension x @a dimension. + * @param dimension Defines how many rows and columns this matrix has. + * @param zero The zero element (default = 0). + */ + CSRGeneralMatrix(count dimension, ValueType zero = 0) + : rowIdx(dimension + 1), columnIdx(0), nonZeros(0), nRows(dimension), nCols(dimension), + isSorted(true), zero(zero) {} + + /** + * Constructs the CSRGeneralMatrix with size @a nRows x @a nCols. + * @param nRows Number of rows. + * @param nCols Number of columns. + * @param zero The zero element (default = 0). + */ + CSRGeneralMatrix(count nRows, count nCols, ValueType zero = 0) + : rowIdx(nRows + 1), columnIdx(0), nonZeros(0), nRows(nRows), nCols(nCols), isSorted(true), + zero(zero) {} + + /** + * Constructs the @a dimension x @a dimension Matrix from the elements at + * position @a positions with values @values. + * @param dimension Defines how many rows and columns this matrix has. + * @param triplets The nonzero elements. + * @param zero The zero element (default is 0). + * @param isSorted True, if the triplets are sorted per row. Default is false. + */ + CSRGeneralMatrix(count dimension, const std::vector &triplets, ValueType zero = 0, + bool isSorted = false) + : CSRGeneralMatrix(dimension, dimension, triplets, zero, isSorted) {} + + /** + * Constructs the @a nRows x @a nCols Matrix from the elements at position @a + * positions with values @values. + * @param nRows Defines how many rows this matrix has. + * @param nCols Defines how many columns this matrix has. + * @param triplets The nonzero elements. + * @param zero The zero element (default is 0). + * @param isSorted True, if the triplets are sorted per row. Default is false. + */ + CSRGeneralMatrix(count nRows, count nCols, const std::vector &triplets, + ValueType zero = 0, bool isSorted = false) + : rowIdx(nRows + 1), columnIdx(triplets.size()), nonZeros(triplets.size()), nRows(nRows), + nCols(nCols), isSorted(isSorted), zero(zero) { + + const count nnz = triplets.size(); + + for (index i = 0; i < nnz; ++i) + rowIdx[triplets[i].row]++; + + for (index i = 0, prefixSum = 0; i < nRows; ++i) { + count nnzInRow = rowIdx[i]; + rowIdx[i] = prefixSum; + prefixSum += nnzInRow; + } + rowIdx[nRows] = nnz; + + for (index i = 0; i < nnz; ++i) { + index row = triplets[i].row; + index dest = rowIdx[row]; + + columnIdx[dest] = triplets[i].column; + nonZeros[dest] = triplets[i].value; + + rowIdx[row]++; + } + + rowIdx.back() = 0; + std::rotate(rowIdx.rbegin(), rowIdx.rbegin() + 1, rowIdx.rend()); + } + + /** + * Constructs the @a nRows x @a nCols Matrix from the elements stored in @a + * columnIdx and @a values. @a columnIdx and @a values store the colums and + * values by row. + * @param nRows + * @param nCols + * @param columnIdx + * @param values + * @param zero The zero element (default is 0). + * @param isSorted True if the column indices in @a columnIdx are sorted in + * every row. + */ + CSRGeneralMatrix(count nRows, count nCols, const std::vector> &columnIdx, + const std::vector> &values, ValueType zero = 0, + bool isSorted = false) + : rowIdx(nRows + 1), nRows(nRows), nCols(nCols), isSorted(isSorted), zero(zero) { + + count nnz = columnIdx[0].size(); + for (index i = 1; i < columnIdx.size(); ++i) { + rowIdx[i] = rowIdx[i - 1] + columnIdx[i - 1].size(); + nnz += columnIdx[i].size(); + } + rowIdx[nRows] = nnz; + + this->columnIdx = std::vector(nnz); + this->nonZeros = std::vector(nnz); + +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(nRows); ++i) { + for (index k = 0; k < columnIdx[i].size(); ++k) { + this->columnIdx[rowIdx[i] + k] = columnIdx[i][k]; + nonZeros[rowIdx[i] + k] = values[i][k]; + } + } + } + + /** + * Constructs the @a nRows x @a nCols Matrix from the elements at position @a + * positions with values @values. + * @param nRows Defines how many rows this matrix has. + * @param nCols Defines how many columns this matrix has. + * @param rowIdx The rowIdx vector of the CSR format. + * @param columnIdx The columnIdx vector of the CSR format. + * @param nonZeros The nonZero vector of the CSR format. Should be as long as + * the @a columnIdx vector. + * @param zero The zero element (default is 0). + * @param isSorted True, if the triplets are sorted per row. Default is false. + */ + CSRGeneralMatrix(count nRows, count nCols, const std::vector &rowIdx, + const std::vector &columnIdx, const std::vector &nonZeros, + ValueType zero = 0, bool isSorted = false) + : rowIdx(rowIdx), columnIdx(columnIdx), nonZeros(nonZeros), nRows(nRows), nCols(nCols), + isSorted(isSorted), zero(zero) {} + + /** Default copy constructor */ + CSRGeneralMatrix(const CSRGeneralMatrix &other) = default; + + /** Default move constructor */ + CSRGeneralMatrix(CSRGeneralMatrix &&other) noexcept = default; + + /** Default destructor */ + ~CSRGeneralMatrix() = default; + + /** Default move assignment operator */ + CSRGeneralMatrix &operator=(CSRGeneralMatrix &&other) noexcept = default; + + /** Default copy assignment operator */ + CSRGeneralMatrix &operator=(const CSRGeneralMatrix &other) = default; + + IndexProxy operator()(index i, index j) { return IndexProxy(*this, i, j); } + + /** + * Compares this matrix to @a other and returns true if the shape and zero + * element are the same as well as + * all entries, otherwise returns false. + * @param other + */ + bool operator==(const CSRGeneralMatrix &other) const { + bool equal = nRows == other.nRows && nCols == other.nCols && zero == other.zero + && nnz() == other.nnz(); + if (equal) + forNonZeroElementsInRowOrder([&](index i, index j, ValueType value) { + if (other(i, j) != value) { + equal = false; + return; + } + }); + + return equal; + } + + /** + * Compares this matrix to @a other and returns true if the shape and zero + * element are the same as well as + * all entries are the same (within the absolute error range of @a eps), otherwise returns + * false. + * @param other + * @param eps + */ + bool isApprox(const CSRGeneralMatrix &other, const double eps = 0.01) const { + bool equal = nRows == other.nRows && nCols == other.nCols && zero == other.zero + && nnz() == other.nnz(); + if (equal) + forNonZeroElementsInRowOrder([&](index i, index j, ValueType value) { + if (std::abs(other(i, j) - value) > eps) { + equal = false; + return; + } + }); + + return equal; + } + + /** + * Compares this matrix to @a other and returns false if the shape and zero + * element are the same as well as + * all entries, otherwise returns true. + * @param other + */ + bool operator!=(const CSRGeneralMatrix &other) const { return !((*this) == other); } + + /** + * @return Number of rows. + */ + count numberOfRows() const noexcept { return nRows; } + + /** + * @return Number of columns. + */ + count numberOfColumns() const noexcept { return nCols; } + + /** + * Returns the zero element of the matrix. + */ + ValueType getZero() const noexcept { return zero; } + + /** + * @param i The row index. + * @return Number of non-zeros in row @a i. + */ + count nnzInRow(const index i) const { + assert(i < nRows); + return rowIdx[i + 1] - rowIdx[i]; + } + + /** + * @return Number of non-zeros in this matrix. + */ + count nnz() const noexcept { return nonZeros.size(); } + + /** + * @return Value at matrix position (i,j). + */ + const ValueType &operator()(index i, index j) const { + assert(i < nRows); + assert(j < nCols); + + if (rowIdx[i] == rowIdx[i + 1]) + return zero; // no non-zero value is present in this row + + if (!sorted()) { + for (index k = rowIdx[i]; k < rowIdx[i + 1]; ++k) { + if (columnIdx[k] == j) { + return nonZeros[k]; + } + } + } else { + // finding the correct index where j should be inserted + auto it = std::lower_bound(columnIdx.begin() + rowIdx[i], + columnIdx.begin() + rowIdx[i + 1], j); + index colIdx = static_cast(it - columnIdx.begin()); + + if (it == columnIdx.end()) + return zero; + else if (*it == j) { + return nonZeros[colIdx]; + } + } + return zero; + } + + /** + * Set the matrix at position (@a i, @a j) to @a value. + * @note This operation can be linear in the number of non-zeros due to vector + * element movements + */ + void setValue(index i, index j, ValueType value) { + assert(i < nRows); + assert(j < nCols); + + index colIdx = none; + + if (!isSorted) { + for (index k = rowIdx[i]; k < rowIdx[i + 1]; ++k) { + if (columnIdx[k] == j) { + colIdx = k; + } + } + if (colIdx != none) { + if (value != zero) { // update existing value + nonZeros[colIdx] = value; + } else { // remove value if set to zero + columnIdx.erase(columnIdx.begin() + colIdx); + nonZeros.erase(nonZeros.begin() + colIdx); + + for (index k = i + 1; k < rowIdx.size(); ++k) { + --rowIdx[k]; + } + } + } else if (value != zero) { // don't add zero values + columnIdx.emplace(std::next(columnIdx.begin(), rowIdx[i + 1]), j); + nonZeros.emplace(std::next(nonZeros.begin(), rowIdx[i + 1]), value); + + // update rowIdx + for (index k = i + 1; k < rowIdx.size(); ++k) { + ++rowIdx[k]; + } + } + } else { + // finding the correct index where j should be inserted + auto it = std::lower_bound(columnIdx.begin() + rowIdx[i], + columnIdx.begin() + rowIdx[i + 1], j); + colIdx = static_cast(it - columnIdx.begin()); + + if (colIdx < rowIdx[i + 1] && columnIdx[colIdx] == j) { + if (value != zero) { // update existing value + nonZeros[colIdx] = value; + } else { // remove value if set to zero + columnIdx.erase(columnIdx.begin() + colIdx); + nonZeros.erase(nonZeros.begin() + colIdx); + + for (index k = i + 1; k < rowIdx.size(); ++k) { + --rowIdx[k]; + } + } + } else if (value != zero) { // don't add zero values + columnIdx.emplace(std::next(columnIdx.begin(), colIdx), j); + nonZeros.emplace(std::next(nonZeros.begin(), colIdx), value); + + // update rowIdx + for (index k = i + 1; k < rowIdx.size(); ++k) { + ++rowIdx[k]; + } + } + } + assert(this->operator()(i, j) == value); + } + + /** + * Sorts the column indices in each row for faster access. + */ + void sort() { +#pragma omp parallel + { + std::vector permutation(nCols); +#pragma omp for schedule(guided) + for (omp_index i = 0; i < static_cast(nRows); ++i) { + const index startOfRow = rowIdx[i], endOfRow = rowIdx[i + 1]; + const count nonZerosInRow = endOfRow - startOfRow; + if (nonZerosInRow <= 1 + || std::is_sorted(columnIdx.begin() + startOfRow, columnIdx.begin() + endOfRow)) + continue; + + permutation.resize(nonZerosInRow); + std::iota(permutation.begin(), permutation.end(), index{0}); + std::ranges::sort(permutation, [&](index x, index y) { + return columnIdx[startOfRow + x] < columnIdx[startOfRow + y]; + }); + + Aux::ArrayTools::applyPermutation(columnIdx.begin() + startOfRow, + columnIdx.begin() + endOfRow, + permutation.begin()); + + Aux::ArrayTools::applyPermutation(nonZeros.begin() + startOfRow, + nonZeros.begin() + endOfRow, permutation.begin()); + } + } + isSorted = true; + +#ifdef NETWORKIT_SANITY_CHECKS +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(nRows); ++i) + assert( + std::is_sorted(columnIdx.begin() + rowIdx[i], columnIdx.begin() + rowIdx[i + 1])); +#endif // NETWORKIT_SANITY_CHECKS + } + + /** + * @return True if the matrix is sorted, otherwise false. + */ + bool sorted() const noexcept { return isSorted; } + + /** + * @return Row @a i of this matrix as vector. + */ + Vector row(index i) const { + assert(i < nRows); + + Vector row(numberOfColumns(), zero, true); + parallelForNonZeroElementsInRow(i, [&row](index j, double value) { row[j] = value; }); + + return row; + } + + /** + * @return Column @a j of this matrix as vector. + */ + Vector column(index j) const { + assert(j < nCols); + + Vector column(numberOfRows(), getZero()); +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(numberOfRows()); ++i) + column[i] = (*this)(i, j); + + return column; + } + + /** + * @return The main diagonal of this matrix. + */ + Vector diagonal() const { + Vector diag(std::min(nRows, nCols), zero); + + if (sorted()) { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(diag.getDimension()); ++i) { + + const auto it = std::lower_bound(columnIdx.begin() + rowIdx[i], + columnIdx.begin() + rowIdx[i + 1], i); + + if (it != columnIdx.end() && *it == static_cast(i)) + diag[i] = nonZeros[it - columnIdx.begin()]; + } + } else { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(diag.getDimension()); ++i) { + diag[i] = (*this)(i, i); + } + } + + return diag; + } + + /** + * Adds this matrix to @a other and returns the result. + * @return The sum of this matrix and @a other. + */ + CSRGeneralMatrix operator+(const CSRGeneralMatrix &other) const { + assert(nRows == other.nRows && nCols == other.nCols); + return CSRGeneralMatrix::binaryOperator( + *this, other, [](double val1, double val2) { return val1 + val2; }); + } + + /** + * Adds @a other to this matrix. + * @return Reference to this matrix. + */ + CSRGeneralMatrix &operator+=(const CSRGeneralMatrix &other) { + assert(nRows == other.nRows && nCols == other.nCols); + *this = CSRGeneralMatrix::binaryOperator( + *this, other, [](double val1, double val2) { return val1 + val2; }); + return *this; + } + + /** + * Subtracts @a other from this matrix and returns the result. + * @return The difference of this matrix and @a other. + * + */ + CSRGeneralMatrix operator-(const CSRGeneralMatrix &other) const { + assert(nRows == other.nRows && nCols == other.nCols); + return CSRGeneralMatrix::binaryOperator( + *this, other, [](double val1, double val2) { return val1 - val2; }); + } + + /** + * Subtracts @a other from this matrix. + * @return Reference to this matrix. + */ + CSRGeneralMatrix &operator-=(const CSRGeneralMatrix &other) { + assert(nRows == other.nRows && nCols == other.nCols); + *this = CSRGeneralMatrix::binaryOperator( + *this, other, [](double val1, double val2) { return val1 - val2; }); + return *this; + } + + /** + * Multiplies this matrix with a scalar specified in @a scalar and returns the + * result. + * @return The result of multiplying this matrix with @a scalar. + */ + CSRGeneralMatrix operator*(const ValueType &scalar) const { + return CSRGeneralMatrix(*this) *= scalar; + } + + /** + * Multiplies this matrix with a scalar specified in @a scalar. + * @return Reference to this matrix. + */ + CSRGeneralMatrix &operator*=(const ValueType &scalar) { +#pragma omp parallel for + for (omp_index k = 0; k < static_cast(nonZeros.size()); ++k) + nonZeros[k] *= scalar; + + return *this; + } + + /** + * Multiplies this matrix with @a vector and returns the result. + * @return The result of multiplying this matrix with @a vector. + */ + Vector operator*(const Vector &vector) const { + assert(!vector.isTransposed()); + assert(nCols == vector.getDimension()); + + Vector result(nRows, zero); +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(numberOfRows()); ++i) { + double sum = zero; + for (index cIdx = rowIdx[i]; cIdx < rowIdx[i + 1]; ++cIdx) { + sum += nonZeros[cIdx] * vector[columnIdx[cIdx]]; + } + result[i] = sum; + } + + return result; + } + + /** + * Multiplies this matrix with @a other and returns the result in a new + * matrix. + * @return The result of multiplying this matrix with @a other. + */ + CSRGeneralMatrix operator*(const CSRGeneralMatrix &other) const { + assert(nCols == other.nRows); + + std::vector rowIdx(numberOfRows() + 1, 0); + std::vector columnIdx; + std::vector nonZeros; + +#pragma omp parallel + { + std::vector marker(other.numberOfColumns(), -1); + count numThreads = omp_get_num_threads(); + index threadId = omp_get_thread_num(); + + count chunkSize = (numberOfRows() + numThreads - 1) / numThreads; + index chunkStart = threadId * chunkSize; + index chunkEnd = std::min(numberOfRows(), chunkStart + chunkSize); + + for (index i = chunkStart; i < chunkEnd; ++i) { + for (index jA = this->rowIdx[i]; jA < this->rowIdx[i + 1]; ++jA) { + index k = this->columnIdx[jA]; + for (index jB = other.rowIdx[k]; jB < other.rowIdx[k + 1]; ++jB) { + index j = other.columnIdx[jB]; + if (marker[j] != (int64_t)i) { + marker[j] = i; + ++rowIdx[i + 1]; + } + } + } + } + + std::ranges::fill(marker, -1); + +#pragma omp barrier +#pragma omp single + { + for (index i = 0; i < numberOfRows(); ++i) + rowIdx[i + 1] += rowIdx[i]; + + columnIdx = std::vector(rowIdx[numberOfRows()]); + nonZeros = std::vector(rowIdx[numberOfRows()]); + } + + for (index i = chunkStart; i < chunkEnd; ++i) { + index rowBegin = rowIdx[i]; + index rowEnd = rowBegin; + + for (index jA = this->rowIdx[i]; jA < this->rowIdx[i + 1]; ++jA) { + index k = this->columnIdx[jA]; + double valA = this->nonZeros[jA]; + + for (index jB = other.rowIdx[k]; jB < other.rowIdx[k + 1]; ++jB) { + index j = other.columnIdx[jB]; + double valB = other.nonZeros[jB]; + + if (marker[j] < (int64_t)rowBegin) { + marker[j] = rowEnd; + columnIdx[rowEnd] = j; + nonZeros[rowEnd] = valA * valB; + ++rowEnd; + } else { + nonZeros[marker[j]] += valA * valB; + } + } + } + } + } + + CSRGeneralMatrix result(numberOfRows(), other.numberOfColumns(), rowIdx, columnIdx, + nonZeros); + if (sorted() && other.sorted()) + result.sort(); + return result; + } + + /** + * Divides this matrix by a divisor specified in @a divisor and returns the + * result in a new matrix. + * @return The result of dividing this matrix by @a divisor. + */ + CSRGeneralMatrix operator/(const ValueType &divisor) const { + return CSRGeneralMatrix(*this) /= divisor; + } + + /** + * Divides this matrix by a divisor specified in @a divisor. + * @return Reference to this matrix. + */ + CSRGeneralMatrix &operator/=(const ValueType &divisor) { return *this *= 1.0 / divisor; } + + /** + * Computes @a A @a binaryOp @a B on the elements of matrix @a A and matrix @a + * B. + * @param A Sorted CSRGeneralMatrix. + * @param B Sorted CSRGeneralMatrix. + * @param binaryOp Function handling (ValueType, ValueType) -> ValueType + * @return @a A @a binaryOp @a B. + * @note @a A and @a B must have the same dimensions and must be sorted. + */ + template + static CSRGeneralMatrix binaryOperator(const CSRGeneralMatrix &A, const CSRGeneralMatrix &B, + L binaryOp); + + /** + * Computes @a A^T * @a B. + * @param A + * @param B + * @return @a A^T * @a B. + * @note The number of rows of @a A must be equal to the number of rows of @a + * B. + */ + static CSRGeneralMatrix mTmMultiply(const CSRGeneralMatrix &A, const CSRGeneralMatrix &B) { + assert(A.nRows == B.nRows); + + std::vector> columnIdx(A.numberOfColumns()); + std::vector> values(A.numberOfColumns()); + + for (index k = 0; k < A.numberOfRows(); ++k) { + A.forNonZeroElementsInRow(k, [&](index i, double vA) { + B.forNonZeroElementsInRow(k, [&](index j, double vB) { + bool found = false; + for (index l = 0; l < columnIdx[i].size(); ++l) { + if (columnIdx[i][l] == j) { + values[i][l] += vA * vB; + found = true; + break; + } + } + + if (!found) { + columnIdx[i].push_back(j); + values[i].push_back(vA * vB); + } + }); + }); + } + + return CSRGeneralMatrix(A.nCols, B.nCols, columnIdx, values); + } + + /** + * Computes @a A * @a B^T. + * @param A + * @param B + * @return @a A * @a B^T. + * @note The number of columns of @a A must be equal to the number of columns + * of @a B. + */ + static CSRGeneralMatrix mmTMultiply(const CSRGeneralMatrix &A, const CSRGeneralMatrix &B) { + assert(A.nCols == B.nCols); + + std::vector> columnIdx(A.numberOfRows()); + std::vector> values(A.numberOfRows()); + + for (index i = 0; i < A.numberOfRows(); ++i) { + A.forNonZeroElementsInRow(i, [&](index k, double vA) { + for (index j = 0; j < B.numberOfRows(); ++j) { + double vB = B(j, k); + if (vB != A.zero) { + bool found = false; + for (index l = 0; l < columnIdx[i].size(); ++l) { + if (columnIdx[i][l] == j) { + values[i][l] += vA * vB; + found = true; + break; + } + } + + if (!found) { + columnIdx[i].push_back(j); + values[i].push_back(vA * vB); + } + } + } + }); + } + + return CSRGeneralMatrix(A.nRows, B.nRows, columnIdx, values); + } + + /** + * Computes @a matrix^T * @a vector. + * @param matrix + * @param vector + * @return @a matrix^T * @a vector. + * @note The number of rows of @a matrix must be equal to the dimension of @a + * vector. + */ + static Vector mTvMultiply(const CSRGeneralMatrix &matrix, const Vector &vector) { + assert(matrix.nRows == vector.getDimension() && !vector.isTransposed()); + + Vector result(matrix.numberOfColumns(), 0); + for (index k = 0; k < matrix.numberOfRows(); ++k) { + matrix.forNonZeroElementsInRow( + k, [&](index j, double value) { result[j] += value * vector[k]; }); + } + + return result; + } + + /** + * Transposes this matrix and returns it. + */ + CSRGeneralMatrix transpose() const { + std::vector rowIdx(numberOfColumns() + 1); + for (index i = 0; i < nnz(); ++i) + ++rowIdx[columnIdx[i] + 1]; + + for (index i = 0; i < numberOfColumns(); ++i) + rowIdx[i + 1] += rowIdx[i]; + + std::vector columnIdx(rowIdx[numberOfColumns()]); + std::vector nonZeros(rowIdx[numberOfColumns()]); + + for (index i = 0; i < numberOfRows(); ++i) { + for (index j = this->rowIdx[i]; j < this->rowIdx[i + 1]; ++j) { + index colIdx = this->columnIdx[j]; + columnIdx[rowIdx[colIdx]] = i; + nonZeros[rowIdx[colIdx]] = this->nonZeros[j]; + ++rowIdx[colIdx]; + } + } + index shift = 0; + for (index i = 0; i < numberOfColumns(); ++i) { + index temp = rowIdx[i]; + rowIdx[i] = shift; + shift = temp; + } + rowIdx[numberOfColumns()] = nonZeros.size(); + + return CSRGeneralMatrix(nCols, nRows, rowIdx, columnIdx, nonZeros, getZero()); + } + + /** + * Extracts a matrix with rows and columns specified by @a rowIndices and @a + * columnIndices from this matrix. + * The order of rows and columns is equal to the order in @a rowIndices and @a + * columnIndices. It is also + * possible to specify a row or column more than once to get duplicates. + * @param rowIndices + * @param columnIndices + */ + CSRGeneralMatrix extract(const std::vector &rowIndices, + const std::vector &columnIndices) const { + std::vector triplets; + std::vector> columnMapping(numberOfColumns()); + for (index j = 0; j < columnIndices.size(); ++j) + columnMapping[columnIndices[j]].push_back(j); + + bool sorted = true; + for (index i = 0; i < rowIndices.size(); ++i) { + Triplet last = {i, 0, 0}; + (*this).forNonZeroElementsInRow(rowIndices[i], [&](index k, double value) { + if (!columnMapping[k].empty()) { + for (index j : columnMapping[k]) { + if (last.row == i && last.column > j) + sorted = false; + last = {i, j, value}; + triplets.push_back(last); + } + } + }); + } + + return CSRGeneralMatrix(rowIndices.size(), columnIndices.size(), triplets, getZero(), + sorted); + } + + /** + * Assign the contents of the matrix @a source to this matrix at rows and + * columns specified by @a rowIndices and + * @a columnIndices. That is, entry (i,j) of @a source is assigned to entry + * (rowIndices[i], columnIndices[j]) of + * this matrix. Note that the dimensions of @rowIndices and @a columnIndices + * must coincide with the number of rows + * and columns of @a source. + * @param rowIndices + * @param columnIndices + * @param source + */ + void assign(const std::vector &rowIndices, const std::vector &columnIndices, + const CSRGeneralMatrix &source) { + assert(rowIndices.size() == source.numberOfRows()); + assert(columnIndices.size() == source.numberOfColumns()); + + for (index i = 0; i < rowIndices.size(); ++i) + source.forElementsInRow(i, [&](index j, double value) { + setValue(rowIndices[i], columnIndices[j], value); + }); + } + + /** + * Applies the unary function @a unaryElementFunction to each value in the + * matrix. Note that it must hold that the + * function applied to the zero element of this matrix returns the zero + * element. + * @param unaryElementFunction + */ + template + void apply(F unaryElementFunction); + + /** + * Compute the (weighted) adjacency matrix of the (weighted) Graph @a graph. + * @param graph + */ + static CSRGeneralMatrix adjacencyMatrix(const Graph &graph, ValueType zero = 0) { + count nonZeros = graph.isDirected() ? graph.numberOfEdges() : graph.numberOfEdges() * 2; + std::vector triplets(nonZeros); + index idx = 0; + graph.forEdges([&](node i, node j, double val) { + triplets[idx++] = {i, j, val}; + if (!graph.isDirected() && i != j) + triplets[idx++] = {j, i, val}; + }); + + return CSRGeneralMatrix(graph.upperNodeIdBound(), triplets, zero); + } + + /** + * Creates a diagonal matrix with dimension equal to the dimension of the + * Vector @a diagonalElements. The values on + * the diagonal are the ones stored in @a diagonalElements (i.e. D(i,i) = + * diagonalElements[i]). + * @param diagonalElements + */ + static CSRGeneralMatrix diagonalMatrix(const Vector &diagonalElements, ValueType zero = 0) { + count nRows = diagonalElements.getDimension(); + count nCols = diagonalElements.getDimension(); + std::vector rowIdx(nRows + 1, 0); + std::iota(rowIdx.begin(), rowIdx.end(), 0); + std::vector columnIdx(nCols); + std::vector nonZeros(nCols); + +#pragma omp parallel for + for (omp_index j = 0; j < static_cast(nCols); ++j) { + columnIdx[j] = j; + nonZeros[j] = diagonalElements[j]; + } + + return CSRGeneralMatrix(nRows, nCols, rowIdx, columnIdx, nonZeros, zero); + } + + /** + * Returns the (weighted) incidence matrix of the (weighted) Graph @a graph. + * @param graph + */ + static CSRGeneralMatrix incidenceMatrix(const Graph &graph, ValueType zero = 0) { + if (!graph.hasEdgeIds()) + throw std::runtime_error("Graph has no edge Ids. Index edges first by " + "calling graph.indexEdges()"); + std::vector triplets; + + if (graph.isDirected()) { + graph.forEdges([&](node u, node v, edgeweight weight, edgeid edgeId) { + if (u != v) { + edgeweight w = std::sqrt(weight); + triplets.push_back({u, edgeId, w}); + triplets.push_back({v, edgeId, -w}); + } + }); + } else { + graph.forEdges([&](node u, node v, edgeweight weight, edgeid edgeId) { + if (u != v) { + edgeweight w = std::sqrt(weight); + if (u < v) { // orientation: small node number -> great node number + triplets.push_back({u, edgeId, w}); + triplets.push_back({v, edgeId, -w}); + } else { + triplets.push_back({u, edgeId, -w}); + triplets.push_back({v, edgeId, w}); + } + } + }); + } + + return CSRGeneralMatrix(graph.upperNodeIdBound(), graph.upperEdgeIdBound(), triplets, zero); + } + + /** + * Compute the (weighted) Laplacian of the (weighted) Graph @a graph. + * @param graph + */ + static CSRGeneralMatrix laplacianMatrix(const Graph &graph, ValueType zero = 0) { + std::vector triples; + + graph.forNodes([&](const index i) { + double weightedDegree = 0; + graph.forNeighborsOf(i, [&](const index j, double weight) { // - adjacency matrix + if (i != j) // exclude diagonal since this would be subtracted by + // the adjacency weight + weightedDegree += weight; + + triples.push_back({i, j, -weight}); + }); + + if (weightedDegree != 0) + triples.push_back({i, i, weightedDegree}); // degree matrix + }); + + return CSRGeneralMatrix(graph.numberOfNodes(), triples, zero); + } + + /** + * Returns the (weighted) normalized Laplacian matrix of the (weighted) Graph + * @a graph + * @param graph + */ + static CSRGeneralMatrix normalizedLaplacianMatrix(const Graph &graph, ValueType zero = 0) { + std::vector triples; + + std::vector weightedDegrees(graph.upperNodeIdBound(), 0); + graph.parallelForNodes([&](const node u) { weightedDegrees[u] = graph.weightedDegree(u); }); + + graph.forNodes([&](const node i) { + graph.forNeighborsOf(i, [&](const node j, double weight) { + if (i != j) + triples.push_back( + {i, j, -weight / std::sqrt(weightedDegrees[i] * weightedDegrees[j])}); + }); + + if (weightedDegrees[i] != 0) { + if (graph.isWeighted()) + triples.push_back({i, i, 1 - (graph.weight(i, i)) / weightedDegrees[i]}); + else + triples.push_back({i, i, 1}); + } + }); + + return CSRGeneralMatrix(graph.upperNodeIdBound(), triples, zero); + } + + /** + * Iterate over all non-zero elements of row @a row in the matrix and call + * handler(index column, ValueType value) + */ + template + void forNonZeroElementsInRow(index row, L handle) const { + for (index k = rowIdx[row]; k < rowIdx[row + 1]; ++k) + handle(columnIdx[k], nonZeros[k]); + } + + /** + * Iterate in parallel over all non-zero elements of row @a row in the matrix + * and call handler(index column, ValueType value) + */ + template + void parallelForNonZeroElementsInRow(index row, L handle) const; + + /** + * Iterate over all elements in row @a i in the matrix and call handle(index + * column, ValueType value) + */ + template + void forElementsInRow(index i, L handle) const; + + /** + * Iterate in parallel over all elements (including zeros) of row @a row in the matrix and call + * handler(index column, double value) + */ + template + void parallelForElementsInRow(index row, L handle) const; + + /** + * Iterate over all elements of the matrix in row order and call handler (lambda + * closure). + */ + template + void forElementsInRowOrder(L handle) const; + + /** + * Iterate in parallel over all rows and call handler (lambda closure) on elements of + * the matrix. + */ + template + void parallelForElementsInRowOrder(L handle) const; + + /** + * Iterate over all non-zero elements of the matrix in row order and call + * handler (lambda closure). + */ + template + void forNonZeroElementsInRowOrder(L handle) const; + + /** + * Iterate in parallel over all rows and call handler (lambda closure) on + * non-zero elements of the matrix. + */ + template + void parallelForNonZeroElementsInRowOrder(L handle) const; +}; + +template +template +inline CSRGeneralMatrix +CSRGeneralMatrix::binaryOperator(const CSRGeneralMatrix &A, + const CSRGeneralMatrix &B, L binaryOp) { + assert(A.nRows == B.nRows && A.nCols == B.nCols); + + if (A.sorted() && B.sorted()) { + std::vector rowIdx(A.nRows + 1); + std::vector> columns(A.nRows); + rowIdx[0] = 0; + +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(A.nRows); ++i) { + index k = A.rowIdx[i]; + index l = B.rowIdx[i]; + while (k < A.rowIdx[i + 1] && l < B.rowIdx[i + 1]) { + if (A.columnIdx[k] < B.columnIdx[l]) { + columns[i].push_back(A.columnIdx[k]); + ++k; + } else if (A.columnIdx[k] > B.columnIdx[l]) { + columns[i].push_back(B.columnIdx[l]); + ++l; + } else { // A.columnIdx[k] == B.columnIdx[l] + columns[i].push_back(A.columnIdx[k]); + ++k; + ++l; + } + ++rowIdx[i + 1]; + } + + while (k < A.rowIdx[i + 1]) { + columns[i].push_back(A.columnIdx[k]); + ++k; + ++rowIdx[i + 1]; + } + + while (l < B.rowIdx[i + 1]) { + columns[i].push_back(B.columnIdx[l]); + ++l; + ++rowIdx[i + 1]; + } + } + + for (index i = 0; i < A.nRows; ++i) + rowIdx[i + 1] += rowIdx[i]; + + count nnz = rowIdx[A.nRows]; + std::vector columnIdx(nnz); + std::vector nonZeros(nnz, A.zero); + +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(A.nRows); ++i) { + for (index cIdx = rowIdx[i], j = 0; cIdx < rowIdx[i + 1]; ++cIdx, ++j) + columnIdx[cIdx] = columns[i][j]; + + columns[i].clear(); + columns[i].resize(0); + columns[i].shrink_to_fit(); + } + +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(A.nRows); ++i) { + index k = A.rowIdx[i]; + index l = B.rowIdx[i]; + for (index cIdx = rowIdx[i]; cIdx < rowIdx[i + 1]; ++cIdx) { + if (k < A.rowIdx[i + 1] && columnIdx[cIdx] == A.columnIdx[k]) { + nonZeros[cIdx] = A.nonZeros[k]; + ++k; + } + + if (l < B.rowIdx[i + 1] && columnIdx[cIdx] == B.columnIdx[l]) { + nonZeros[cIdx] = binaryOp(nonZeros[cIdx], B.nonZeros[l]); + ++l; + } + } + } + + return CSRGeneralMatrix(A.nRows, A.nCols, rowIdx, columnIdx, nonZeros, A.zero, true); + } else { // A or B not sorted + std::vector columnPointer(A.nCols, -1); + std::vector Arow(A.nCols, A.zero); + std::vector Brow(A.nCols, B.zero); + + std::vector triplets; + + for (index i = 0; i < A.nRows; ++i) { + index listHead = 0; + count nnz = 0; + + // search for nonZeros in our own matrix + for (index k = A.rowIdx[i]; k < A.rowIdx[i + 1]; ++k) { + index j = A.columnIdx[k]; + Arow[j] = A.nonZeros[k]; + + columnPointer[j] = listHead; + listHead = j; + nnz++; + } + + // search for nonZeros in the other matrix + for (index k = B.rowIdx[i]; k < B.rowIdx[i + 1]; ++k) { + index j = B.columnIdx[k]; + Brow[j] = B.nonZeros[k]; + + if (columnPointer[j] + == -1) { // our own matrix does not have a nonZero entry in column j + columnPointer[j] = listHead; + listHead = j; + nnz++; + } + } + + // apply operator on the found nonZeros in A and B + for (count k = 0; k < nnz; ++k) { + ValueType value = binaryOp(Arow[listHead], Brow[listHead]); + if (value != A.zero) + triplets.push_back({i, listHead, value}); + + index temp = listHead; + listHead = columnPointer[listHead]; + + // reset for next row + columnPointer[temp] = -1; + Arow[temp] = A.zero; + Brow[temp] = B.zero; + } + + nnz = 0; + } + + return CSRGeneralMatrix(A.numberOfRows(), A.numberOfColumns(), triplets); + } +} + +template +template +void CSRGeneralMatrix::apply(const F unaryElementFunction) { +#pragma omp parallel for + for (omp_index k = 0; k < static_cast(nonZeros.size()); ++k) + nonZeros[k] = unaryElementFunction(nonZeros[k]); +} + +template +template +inline void CSRGeneralMatrix::parallelForNonZeroElementsInRow(index i, L handle) const { +#pragma omp parallel for + for (omp_index k = rowIdx[i]; k < static_cast(rowIdx[i + 1]); ++k) + handle(columnIdx[k], nonZeros[k]); +} + +template +template +inline void CSRGeneralMatrix::forElementsInRow(index i, L handle) const { + Vector rowVector = row(i); + index j = 0; + rowVector.forElements([&](ValueType val) { handle(j++, val); }); +} + +template +template +inline void CSRGeneralMatrix::parallelForElementsInRow(index i, L handle) const { + row(i).parallelForElements(handle); +} + +template +template +inline void CSRGeneralMatrix::forElementsInRowOrder(L handle) const { + for (index i = 0; i < nRows; ++i) { + index col = 0; + for (index k = rowIdx[i]; k < rowIdx[i + 1]; ++k) { + while (col < columnIdx[k]) { + handle(i, col, getZero()); + ++col; + } + handle(i, col, nonZeros[k]); + ++col; + } + } +} + +template +template +inline void CSRGeneralMatrix::parallelForElementsInRowOrder(L handle) const { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(nRows); ++i) { + index col = 0; + for (index k = rowIdx[i]; k < rowIdx[i + 1]; ++k) { + while (col < columnIdx[k]) { + handle(i, col, getZero()); + ++col; + } + handle(i, col, nonZeros[k]); + ++col; + } + } +} + +template +template +inline void CSRGeneralMatrix::forNonZeroElementsInRowOrder(L handle) const { + for (index i = 0; i < nRows; ++i) + for (index k = rowIdx[i]; k < rowIdx[i + 1]; ++k) + handle(i, columnIdx[k], nonZeros[k]); +} + +template +template +inline void CSRGeneralMatrix::parallelForNonZeroElementsInRowOrder(L handle) const { + for (omp_index i = 0; i < static_cast(nRows); ++i) + for (index k = rowIdx[i]; k < rowIdx[i + 1]; ++k) + handle(i, columnIdx[k], nonZeros[k]); +} + +// print functions for test debugging / output +template +inline std::ostream &operator<<(std::ostream &os, const CSRGeneralMatrix &M) { + for (index row = 0; row < M.numberOfRows(); ++row) { + if (row != 0) + os << std::endl; + for (index col = 0; col < M.numberOfColumns(); ++col) { + if (col != 0) + os << ", "; + os << M(row, col); + } + } + return os; +} + +} /* namespace NetworKit */ +#endif // NETWORKIT_ALGEBRAIC_CSR_GENERAL_MATRIX_HPP_ diff --git a/vendor/include/networkit/algebraic/CSRMatrix.hpp b/vendor/include/networkit/algebraic/CSRMatrix.hpp new file mode 100644 index 0000000..9cd4c00 --- /dev/null +++ b/vendor/include/networkit/algebraic/CSRMatrix.hpp @@ -0,0 +1,11 @@ +#ifndef NETWORKIT_ALGEBRAIC_CSR_MATRIX_HPP_ +#define NETWORKIT_ALGEBRAIC_CSR_MATRIX_HPP_ + +#include + +// For compatibility with the previous CSRMatrix implementation. +namespace NetworKit { +using CSRMatrix = CSRGeneralMatrix; +} // namespace NetworKit + +#endif // NETWORKIT_ALGEBRAIC_CSR_MATRIX_HPP_ diff --git a/vendor/include/networkit/algebraic/DenseMatrix.hpp b/vendor/include/networkit/algebraic/DenseMatrix.hpp new file mode 100644 index 0000000..cf036fe --- /dev/null +++ b/vendor/include/networkit/algebraic/DenseMatrix.hpp @@ -0,0 +1,537 @@ +/* + * DenseMatrix.hpp + * + * Created on: Nov 25, 2015 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_DENSE_MATRIX_HPP_ +#define NETWORKIT_ALGEBRAIC_DENSE_MATRIX_HPP_ + +#include +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * Represents a dense matrix. Use this matrix to run LU decompositions and LU solves. + * Note that most matrices are rather sparse s.t. CSRMatrix might be a better representation. + */ +class DenseMatrix final { +private: + count nRows; + count nCols; + std::vector entries; + double zero; + +public: + /** Default constructor */ + DenseMatrix(); + + /** + * Constructs the DenseMatrix with size @a dimension x @a dimension. + * @param dimension Defines how many rows and columns this matrix has. + * @param zero The zero element (default is 0.0). + */ + DenseMatrix(count dimension, double zero = 0.0); + + /** + * Constructs the DenseMatrix with size @a nRows x @a nCols. + * @param nRows Number of rows. + * @param nCols Number of columns. + * @param zero The zero element (default is 0.0). + */ + DenseMatrix(count nRows, count nCols, double zero = 0.0); + + /** + * Constructs the @a dimension x @a dimension DenseMatrix from the elements at position @a + * positions with values @values. + * @param dimension Defines how many rows and columns this matrix has. + * @param triplets The nonzero elements. + * @param zero The zero element (default is 0.0). + */ + DenseMatrix(count dimension, const std::vector &triplets, double zero = 0.0); + + /** + * Constructs the @a nRows x @a nCols DenseMatrix from the elements at position @a positions + * with values @values. + * @param nRows Defines how many rows this matrix has. + * @param nCols Defines how many columns this matrix has. + * @param triplets The nonzero elements. + * @param zero The zero element (default is 0.0). + */ + DenseMatrix(count nRows, count nCols, const std::vector &triplets, double zero = 0.0); + + /** + * Constructs an instance of DenseMatrix given the number of rows (@a nRows) and the number of + * columns (@a nCols) and its values (@a entries). + * @param nRows Number of rows. + * @param nCols Number of columns. + * @param entries Entries of the matrix. + * @param zero The zero element (default is 0.0). + * @note The size of the @a entries vector should be equal to @a nRows * @a nCols. + */ + DenseMatrix(count nRows, count nCols, const std::vector &entries, double zero = 0.0); + + /** Default destructor */ + ~DenseMatrix() = default; + + /** Default copy constructor */ + DenseMatrix(const DenseMatrix &other) = default; + + /** Default move constructor */ + DenseMatrix(DenseMatrix &&other) = default; + + /** Default copy assignment operator */ + DenseMatrix &operator=(DenseMatrix &&other) = default; + + /** Default move assignment operator */ + DenseMatrix &operator=(const DenseMatrix &other) = default; + + /** + * Compares this matrix to @a other and returns true if the shapes and entries are the same, + * otherwise returns false. + * @param other + */ + bool operator==(const DenseMatrix &other) const { + bool equal = + nRows == other.nRows && nCols == other.nCols && entries.size() == other.entries.size(); + if (equal) { + forElementsInRowOrder([&](index i, index j, double value) { + if (other(i, j) != value) { + equal = false; + return; + } + }); + } + return equal; + } + + /** + * Compares this matrix to @a other and returns true if the shape and zero + * element are the same as well as + * all entries are the same (within the absolute error range of @a eps), otherwise returns + * false. + * @param other + * @param eps + */ + bool isApprox(const DenseMatrix &other, const double eps = 0.01) const { + bool equal = + nRows == other.nRows && nCols == other.nCols && entries.size() == other.entries.size(); + if (equal) { + forElementsInRowOrder([&](index i, index j, double value) { + if (std::abs(other(i, j) - value) > eps) { + equal = false; + return; + } + }); + } + return equal; + } + + /** + * @return Number of rows. + */ + inline count numberOfRows() const { return nRows; } + + /** + * @return Number of columns. + */ + inline count numberOfColumns() const { return nCols; } + + /** + * Returns the zero element of the matrix. + */ + inline double getZero() const { return zero; } + + /** + * @param i The row index. + * @return Number of non-zeros in row @a i. + * @note This function is linear in the number of columns of the matrix. + */ + count nnzInRow(index i) const; + + /** + * @return Number of non-zeros in this matrix. + * @note This function takes nRows * nCols operations. + */ + count nnz() const; + + /** + * @return Value at matrix position (i,j). + */ + double operator()(index i, index j) const; + + /** + * Set the matrix at position (@a i, @a j) to @a value. + */ + double &operator()(index i, index j); + + /** + * Set the matrix at position (@a i, @a j) to @a value. + */ + void setValue(index i, index j, double value); + + /** + * @return Row @a i of this matrix as vector. + */ + Vector row(index i) const; + + /** + * @return Column @a j of this matrix as vector. + */ + Vector column(index j) const; + + /** + * @return The main diagonal of this matrix. + */ + Vector diagonal() const; + + /** + * Adds this matrix to @a other and returns the result. + * @return The sum of this matrix and @a other. + */ + DenseMatrix operator+(const DenseMatrix &other) const; + + /** + * Adds @a other to this matrix. + * @return Reference to this matrix. + */ + DenseMatrix &operator+=(const DenseMatrix &other); + + /** + * Subtracts @a other from this matrix and returns the result. + * @return The difference of this matrix and @a other. + * + */ + DenseMatrix operator-(const DenseMatrix &other) const; + + /** + * Subtracts @a other from this matrix. + * @return Reference to this matrix. + */ + DenseMatrix &operator-=(const DenseMatrix &other); + + /** + * Multiplies this matrix with a scalar specified in @a scalar and returns the result. + * @return The result of multiplying this matrix with @a scalar. + */ + DenseMatrix operator*(double scalar) const; + + /** + * Multiplies this matrix with a scalar specified in @a scalar. + * @return Reference to this matrix. + */ + DenseMatrix &operator*=(double scalar); + + /** + * Multiplies this matrix with @a vector and returns the result. + * @return The result of multiplying this matrix with @a vector. + */ + Vector operator*(const Vector &vector) const; + + /** + * Multiplies this matrix with @a other and returns the result in a new matrix. + * @return The result of multiplying this matrix with @a other. + */ + DenseMatrix operator*(const DenseMatrix &other) const; + + /** + * Divides this matrix by a divisor specified in @a divisor and returns the result in a new + * matrix. + * @return The result of dividing this matrix by @a divisor. + */ + DenseMatrix operator/(double divisor) const; + + /** + * Divides this matrix by a divisor specified in @a divisor. + * @return Reference to this matrix. + */ + DenseMatrix &operator/=(double divisor); + + /** + * Transposes this matrix and returns it. + */ + DenseMatrix transpose() const; + + /** + * Extracts a matrix with rows and columns specified by @a rowIndices and @a columnIndices from + * this matrix. The order of rows and columns is equal to the order in @a rowIndices and @a + * columnIndices. It is also possible to specify a row or column more than once to get + * duplicates. + * @param rowIndices + * @param columnIndices + */ + DenseMatrix extract(const std::vector &rowIndices, + const std::vector &columnIndices) const; + + /** + * Assign the contents of the matrix @a source to this matrix at rows and columns specified by + * @a rowIndices and + * @a columnIndices. That is, entry (i,j) of @a source is assigned to entry (rowIndices[i], + * columnIndices[j]) of this matrix. Note that the dimensions of @rowIndices and @a + * columnIndices must coincide with the number of rows and columns of @a source. + * @param rowIndices + * @param columnIndices + * @param source + */ + void assign(const std::vector &rowIndices, const std::vector &columnIndices, + const DenseMatrix &source); + + /** + * Applies the unary function @a unaryElementFunction to each value in the matrix. Note that it + * must hold that the function applied to the zero element of this matrix returns the zero + * element. + * @param unaryElementFunction + */ + template + void apply(F unaryElementFunction); + + /** + * Returns the (weighted) adjacency matrix of the (weighted) Graph @a graph. + * @param graph + */ + static DenseMatrix adjacencyMatrix(const Graph &graph, double zero = 0.0); + + /** + * Creates a diagonal matrix with dimension equal to the dimension of the Vector @a + * diagonalElements. The values on the diagonal are the ones stored in @a diagonalElements (i.e. + * D(i,i) = diagonalElements[i]). + * @param diagonalElements + */ + static DenseMatrix diagonalMatrix(const Vector &diagonalElements, double zero = 0.0); + + /** + * Returns the (weighted) incidence matrix of the (weighted) Graph @a graph. + * @param graph + */ + static DenseMatrix incidenceMatrix(const Graph &graph, double zero = 0.0); + + /** + * Returns the (weighted) Laplacian matrix of the (weighteD) Graph @a graph. + * @param graph + */ + static DenseMatrix laplacianMatrix(const Graph &graph, double zero = 0.0); + + /** + * Decomposes the given @a matrix into lower L and upper U matrix (in-place). + * @param matrix The matrix to decompose into LU. + */ + static void LUDecomposition(DenseMatrix &matrix); + + /** + * Computes the solution vector x to the system @a LU * x = @a b where @a LU is a matrix + * decomposed into L and U. + * @param LU Matrix decomposed into lower L and upper U matrix. + * @param b Right-hand side. + * @return Solution vector x to the linear equation system LU * x = b. + */ + static Vector LUSolve(const DenseMatrix &LU, const Vector &b); + + /** + * Computes @a A @a binaryOp @a B on the elements of matrix @a A and matrix @a B. + * @param A + * @param B + * @param binaryOp Function handling (double, double) -> double + * @return @a A @a binaryOp @a B. + * @note @a A and @a B must have the same dimensions. + */ + template + static DenseMatrix binaryOperator(const DenseMatrix &A, const DenseMatrix &B, L binaryOp); + + /** + * Iterate over all elements of row @a row in the matrix and call handler(index column, + * double value) + */ + template + void forElementsInRow(index row, L handle) const; + + /** + * Iterate in parallel over all elements of row @a row in the matrix and call + * handler(index column, double value) + */ + template + void parallelForElementsInRow(index row, L handle) const; + + /** + * Iterate over all elements of the matrix in row order and call handler (lambda + * closure). + */ + template + void forElementsInRowOrder(L handle) const; + + /** + * Iterate in parallel over all rows and call handler (lambda closure) on elements of + * the matrix. + */ + template + void parallelForElementsInRowOrder(L handle) const; + + /** + * Iterate over all non-zero elements of row @a row in the matrix and call handler(index column, + * double value). + * @note This is a DenseMatrix! Therefore this operation needs O(numberOfRows()) time regardless + * of the number of non-zeros actually present. + */ + template + void forNonZeroElementsInRow(index row, L handle) const; + + /** + * Iterate in parallel over all non-zero elements of row @a row in the matrix and call + * handler(index column, double value) + * @note This is a DenseMatrix! Therefore this operation needs O(numberOfRows()) sequential time + * regardless of the number of non-zeros actually present. + */ + template + void parallelForNonZeroElementsInRow(index row, L handle) const; + + /** + * Iterate over all non-zero elements of the matrix in row order and call handler (lambda + * closure). + * @note This is a DenseMatrix! Therefore this operation needs O(numberOfRows() * + * numberOfColumns()) time regardless of the number of non-zeros actually present. + */ + template + void forNonZeroElementsInRowOrder(L handle) const; + + /** + * Iterate in parallel over all rows and call handler (lambda closure) on non-zero elements of + * the matrix. + * @note This is a DenseMatrix! Therefore this operation needs O(numberOfRows() * + * numberOfColumns()) sequential time regardless of the number of non-zeros actually present. + */ + template + void parallelForNonZeroElementsInRowOrder(L handle) const; +}; + +template +void DenseMatrix::apply(F unaryElementFunction) { +#pragma omp parallel for + for (omp_index k = 0; k < static_cast(entries.size()); ++k) { + entries[k] = unaryElementFunction(entries[k]); + } +} + +template +inline DenseMatrix DenseMatrix::binaryOperator(const DenseMatrix &A, const DenseMatrix &B, + L binaryOp) { + assert(A.nRows == B.nRows && A.nCols == B.nCols); + + std::vector resultEntries(A.numberOfRows() * A.numberOfColumns(), 0.0); + +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(A.numberOfRows()); ++i) { + index offset = i * A.numberOfColumns(); + for (index j = offset; j < offset + A.numberOfColumns(); ++j) { + resultEntries[j] = binaryOp(A.entries[j], B.entries[j]); + } + } + + return DenseMatrix(A.numberOfRows(), A.numberOfColumns(), resultEntries); +} + +template +inline void DenseMatrix::forElementsInRow(index i, L handle) const { + index offset = i * numberOfColumns(); + for (index k = offset, j = 0; k < offset + numberOfColumns(); ++k, ++j) { + handle(j, entries[k]); + } +} + +template +inline void DenseMatrix::parallelForElementsInRow(index i, L handle) const { + index offset = i * numberOfColumns(); +#pragma omp parallel for + for (omp_index j = 0; j < static_cast(numberOfColumns()); ++j) { + handle(j, entries[offset + j]); + } +} + +template +inline void DenseMatrix::forElementsInRowOrder(L handle) const { + for (index i = 0; i < nRows; ++i) { + index offset = i * numberOfColumns(); + for (index k = offset, j = 0; k < offset + numberOfColumns(); ++k, ++j) { + handle(i, j, entries[k]); + } + } +} + +template +inline void DenseMatrix::parallelForElementsInRowOrder(L handle) const { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(nRows); ++i) { + index offset = i * numberOfColumns(); + for (index k = offset, j = 0; k < offset + numberOfColumns(); ++k, ++j) { + handle(i, j, entries[k]); + } + } +} + +template +inline void DenseMatrix::forNonZeroElementsInRow(index row, L handle) const { + for (index j = 0, k = row * numberOfColumns(); j < numberOfColumns(); ++j, ++k) { + if (entries[k] != getZero()) { + handle(j, entries[k]); + } + } +} + +template +inline void DenseMatrix::parallelForNonZeroElementsInRow(index row, L handle) const { +#pragma omp parallel for + for (omp_index j = 0; j < static_cast(numberOfColumns()); ++j) { + index k = row * numberOfColumns() + j; + if (entries[k] != getZero()) { + handle(j, entries[k]); + } + } +} + +template +inline void DenseMatrix::forNonZeroElementsInRowOrder(L handle) const { + for (index i = 0; i < numberOfRows(); ++i) { + for (index j = 0, k = i * numberOfColumns(); j < numberOfColumns(); ++j, ++k) { + if (entries[k] != getZero()) { + handle(i, j, entries[k]); + } + } + } +} + +template +inline void DenseMatrix::parallelForNonZeroElementsInRowOrder(L handle) const { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(numberOfRows()); ++i) { + for (index j = 0, k = i * numberOfColumns(); j < numberOfColumns(); ++j, ++k) { + if (entries[k] != getZero()) { + handle(i, j, entries[k]); + } + } + } +} + +// print functions for test debugging / output +inline std::ostream &operator<<(std::ostream &os, const DenseMatrix &M) { + for (index row = 0; row < M.numberOfRows(); ++row) { + if (row != 0) + os << std::endl; + for (index col = 0; col < M.numberOfColumns(); ++col) { + if (col != 0) + os << ", "; + os << M(row, col); + } + } + return os; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_ALGEBRAIC_DENSE_MATRIX_HPP_ diff --git a/vendor/include/networkit/algebraic/DynamicMatrix.hpp b/vendor/include/networkit/algebraic/DynamicMatrix.hpp new file mode 100644 index 0000000..8702e91 --- /dev/null +++ b/vendor/include/networkit/algebraic/DynamicMatrix.hpp @@ -0,0 +1,514 @@ +/* + * DynamicMatrix.hpp + * + * Created on: 13.03.2014 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_DYNAMIC_MATRIX_HPP_ +#define NETWORKIT_ALGEBRAIC_DYNAMIC_MATRIX_HPP_ + +#include + +#include +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * The DynamicMatrix class represents a matrix that is optimized for sparse matrices and internally + * uses a graph data structure. DynamicMatrix should be used when changes to the structure of the + * matrix are frequent. + */ +class DynamicMatrix final { +protected: + GraphW graph; + + count nRows; + count nCols; + + double zero; + + // necessary for operator() const to allow for index addressing via DynamicMatrix(i,j) = value + class IndexProxy { + public: + IndexProxy(DynamicMatrix &mat, index i, index j) : Matrix{mat}, i{i}, j{j} {} + + operator double() const { return const_cast(Matrix)(i, j); } + + void operator=(double rhs) { Matrix.setValue(i, j, rhs); } + + private: + DynamicMatrix &Matrix; + index i; + index j; + }; + +public: + /** Default constructor */ + DynamicMatrix(); + + /** + * Constructs the Matrix with size @a dimension x @a dimension. + * @param dimension Defines how many rows and columns this matrix has. + * @param zero The zero element (default is 0.0). + */ + DynamicMatrix(count dimension, double zero = 0.0); + + /** + * Constructs the Matrix with size @a nRows x @a nCols. + * @param nRows Number of rows. + * @param nCols Number of columns. + * @param zero The zero element (default is 0.0). + */ + DynamicMatrix(count nRows, count nCols, double zero = 0.0); + + /** + * Constructs the @a dimension x @a dimension Matrix from the elements at position @a positions + * with values @values. + * @param dimension Defines how many rows and columns this matrix has. + * @param triplets The nonzero elements. + * @param zero The zero element (default is 0.0). + */ + DynamicMatrix(count dimension, const std::vector &triplets, double zero = 0.0); + + /** + * Constructs the @a nRows x @a nCols Matrix from the elements at position @a positions with + * values @values. + * @param nRows Defines how many rows this matrix has. + * @param nCols Defines how many columns this matrix has. + * @param triplets The nonzero elements. + * @param zero The zero element (default is 0.0). + */ + DynamicMatrix(count nRows, count nCols, const std::vector &triplets, + double zero = 0.0); + + /** + * Compares this matrix to @a other and returns true if the shape and zero element are the same + * as well as all entries, otherwise returns false. + * @param other + */ + bool operator==(const DynamicMatrix &other) const { + bool graphsEqual = graph.numberOfNodes() == other.graph.numberOfNodes() + && graph.numberOfEdges() == other.graph.numberOfEdges(); + if (graphsEqual) { + graph.forEdges([&](node u, node v, edgeweight w) { + if (w != other.graph.weight(u, v)) { + graphsEqual = false; + return; + } + }); + } + + return graphsEqual && nRows == other.nRows && nCols == other.nCols && zero == other.zero; + } + + /** + * Compares this matrix to @a other and returns true if the shape and zero + * element are the same as well as + * all entries are the same (within the absolute error range of @a eps), otherwise returns + * false. + * @param other + * @param eps + */ + bool isApprox(const DynamicMatrix &other, const double eps = 0.01) const { + bool graphsEqual = graph.numberOfNodes() == other.graph.numberOfNodes() + && graph.numberOfEdges() == other.graph.numberOfEdges(); + if (graphsEqual) { + graph.forEdges([&](node u, node v, edgeweight w) { + if (std::abs(w - other.graph.weight(u, v)) > eps) { + graphsEqual = false; + return; + } + }); + } + + return graphsEqual && nRows == other.nRows && nCols == other.nCols && zero == other.zero; + } + + /** + * Compares this matrix to @a other and returns false if the shape and zero element are the same + * as well as all entries, otherwise returns true. + * @param other + */ + bool operator!=(const DynamicMatrix &other) const { return !((*this) == other); } + + /** + * @return Number of rows. + */ + inline count numberOfRows() const { return nRows; } + + /** + * @return Number of columns. + */ + inline count numberOfColumns() const { return nCols; } + + /** + * Returns the zero element of the matrix. + */ + inline double getZero() const { return zero; } + + /** + * @param i The row index. + * @return Number of non-zeros in row @a i. + */ + count nnzInRow(index i) const; + + /** + * @return Number of non-zeros in this matrix. + */ + count nnz() const; + + /** + * @return Value at matrix position (i,j). + */ + double operator()(index i, index j) const; + + /** + * Set the matrix at position (@a i, @a j) to @a value. + */ + IndexProxy operator()(index i, index j) { return IndexProxy(*this, i, j); } + + /** + * Set the matrix at position (@a i, @a j) to @a value. + */ + void setValue(index i, index j, double value); + + /** + * @return Row @a i of this matrix as vector. + */ + Vector row(index i) const; + + /** + * @return Column @a j of this matrix as vector. + */ + Vector column(index j) const; + + /** + * @return The main diagonal of this matrix. + */ + Vector diagonal() const; + + /** + * Adds this matrix to @a other and returns the result. + * @return The sum of this matrix and @a other. + */ + DynamicMatrix operator+(const DynamicMatrix &other) const; + + /** + * Adds @a other to this matrix. + * @return Reference to this matrix. + */ + DynamicMatrix &operator+=(const DynamicMatrix &other); + + /** + * Subtracts @a other from this matrix and returns the result. + * @return The difference of this matrix and @a other. + * + */ + DynamicMatrix operator-(const DynamicMatrix &other) const; + + /** + * Subtracts @a other from this matrix. + * @return Reference to this matrix. + */ + DynamicMatrix &operator-=(const DynamicMatrix &other); + + /** + * Multiplies this matrix with a scalar specified in @a scalar and returns the result. + * @return The result of multiplying this matrix with @a scalar. + */ + DynamicMatrix operator*(double scalar) const; + + /** + * Multiplies this matrix with a scalar specified in @a scalar. + * @return Reference to this matrix. + */ + DynamicMatrix &operator*=(double scalar); + + /** + * Multiplies this matrix with @a vector and returns the result. + * @return The result of multiplying this matrix with @a vector. + */ + Vector operator*(const Vector &vector) const; + + /** + * Multiplies this matrix with @a other and returns the result in a new matrix. + * @return The result of multiplying this matrix with @a other. + */ + DynamicMatrix operator*(const DynamicMatrix &other) const; + + /** + * Divides this matrix by a divisor specified in @a divisor and returns the result in a new + * matrix. + * @return The result of dividing this matrix by @a divisor. + */ + DynamicMatrix operator/(double divisor) const; + + /** + * Divides this matrix by a divisor specified in @a divisor. + * @return Reference to this matrix. + */ + DynamicMatrix &operator/=(double divisor); + + /** + * Computes A^T * B. + * @param A + * @param B + */ + static DynamicMatrix mTmMultiply(const DynamicMatrix &A, const DynamicMatrix &B); + + /** + * Computes A * B^T. + * @param A + * @param B + */ + static DynamicMatrix mmTMultiply(const DynamicMatrix &A, const DynamicMatrix &B); + + /** + * Computes matrix^T * vector + * @param matrix + * @param vector + */ + static Vector mTvMultiply(const DynamicMatrix &matrix, const Vector &vector); + + /** + * Transposes this matrix and returns it. + */ + DynamicMatrix transpose() const; + + /** + * Extracts a matrix with rows and columns specified by @a rowIndices and @a columnIndices from + * this matrix. The order of rows and columns is equal to the order in @a rowIndices and @a + * columnIndices. It is also possible to specify a row or column more than once to get + * duplicates. + * @param rowIndices + * @param columnIndices + */ + DynamicMatrix extract(const std::vector &rowIndices, + const std::vector &columnIndices) const; + + /** + * Assign the contents of the matrix @a source to this matrix at rows and columns specified by + * @a rowIndices and + * @a columnIndices. That is, entry (i,j) of @a source is assigned to entry (rowIndices[i], + * columnIndices[j]) of this matrix. Note that the dimensions of @rowIndices and @a + * columnIndices must coincide with the number of rows and columns of @a source. + * @param rowIndices + * @param columnIndices + * @param source + */ + void assign(const std::vector &rowIndices, const std::vector &columnIndices, + const DynamicMatrix &source); + + /** + * Applies the unary function @a unaryElementFunction to each value in the matrix. Note that it + * must hold that the function applied to the zero element of this matrix returns the zero + * element. + * @param unaryElementFunction + */ + template + void apply(F unaryElementFunction); + + /** + * Returns the (weighted) adjacency matrix of the (weighted) Graph @a graph. + * @param graph + */ + static DynamicMatrix adjacencyMatrix(const Graph &graph, double zero = 0.0); + + /** + * Creates a diagonal matrix with dimension equal to the dimension of the Vector @a + * diagonalElements. The values on the diagonal are the ones stored in @a diagonalElements (i.e. + * D(i,i) = diagonalElements[i]). + * @param diagonalElements + */ + static DynamicMatrix diagonalMatrix(const Vector &diagonalElements, double zero = 0.0); + + /** + * Returns the (weighted) incidence matrix of the (weighted) Graph @a graph. + * @param graph + */ + static DynamicMatrix incidenceMatrix(const Graph &graph, double zero = 0.0); + + /** + * Returns the (weighted) Laplacian matrix of the (weighteD) Graph @a graph. + * @param graph + */ + static DynamicMatrix laplacianMatrix(const Graph &graph, double zero = 0.0); + + /** + * Returns the (weighted) normalized Laplacian matrix of the (weighted) Graph @a graph + * @param graph + */ + static DynamicMatrix normalizedLaplacianMatrix(const Graph &graph, double zero = 0.0); + + /** + * Iterate over all non-zero elements of row @a row in the matrix and call handle(index row, + * index column, double value) + */ + template + void forNonZeroElementsInRow(index row, L handle) const; + + /** + * Iterate in parallel over all non-zero elements of row @a row in the matrix and call + * handler(index column, double value) + */ + template + void parallelForNonZeroElementsInRow(index i, L handle) const; + + /** + * Iterate over all elements in row @a i in the matrix and call handle(index column, double + * value) + */ + template + void forElementsInRow(index i, L handle) const; + + /** + * Iterate in parallel over all elements (including zeros) of row @a row in the matrix and call + * handler(index column, double value) + */ + template + void parallelForElementsInRow(index row, L handle) const; + + /** + * Iterate over all elements (including zeros) of the matrix in row order and call handler + * (lambda closure). + */ + template + void forElementsInRowOrder(L handle) const; + + /** + * Iterate in parallel over all elements (including zeros) in row order and call handle + * (lambda closure) on elements of the matrix. + */ + template + void parallelForElementsInRowOrder(L handle) const; + + /** + * Iterate over all non-zero elements of the matrix in row order and call handle(index row, + * index column, double value). + */ + template + void forNonZeroElementsInRowOrder(L handle) const; + + /** + * Iterate in parallel over all rows and call handle(index row, index column, double value) on + * non-zero elements of the matrix. + */ + template + void parallelForNonZeroElementsInRowOrder(L handle) const; +}; + +template +void NetworKit::DynamicMatrix::apply(F unaryElementFunction) { + forNonZeroElementsInRowOrder( + [&](index i, index j, double value) { setValue(i, j, unaryElementFunction(value)); }); +} + +template +inline void NetworKit::DynamicMatrix::forNonZeroElementsInRow(index row, L handle) const { + graph.forEdgesOf(row, [&](index j, edgeweight weight) { handle(j, weight); }); +} + +template +inline void NetworKit::DynamicMatrix::parallelForNonZeroElementsInRow(index i, L handle) const { + std::vector> elements(graph.weightNeighborRange(i).begin(), + graph.weightNeighborRange(i).end()); +#pragma omp parallel for + for (omp_index j = 0; j < static_cast(elements.size()); ++j) { + handle(elements[j].first, elements[j].second); + } +} + +template +inline void NetworKit::DynamicMatrix::forElementsInRow(index i, L handle) const { + Vector rowVector = row(i); + index j = 0; + rowVector.forElements([&](double value) { handle(j++, value); }); +} + +template +inline void NetworKit::DynamicMatrix::parallelForElementsInRow(index i, L handle) const { + Vector rowVector = row(i); +#pragma omp parallel for + for (omp_index j = 0; j < static_cast(rowVector.getDimension()); ++j) { + handle(j, rowVector[j]); + } +} + +template +inline void NetworKit::DynamicMatrix::forElementsInRowOrder(L handle) const { + for (index i = 0; i < nRows; ++i) { + index col = 0; + graph.forEdgesOf(i, [&](index j, edgeweight weight) { + while (col < j) { + handle(i, col, getZero()); + ++col; + } + handle(i, col, weight); + ++col; + }); + + while (col < i) { + handle(i, col, getZero()); + ++col; + } + } +} + +template +inline void NetworKit::DynamicMatrix::parallelForElementsInRowOrder(L handle) const { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(nRows); ++i) { + index col = 0; + graph.forEdgesOf(i, [&](index j, edgeweight weight) { + while (col < j) { + handle(i, col, getZero()); + ++col; + } + handle(i, col, weight); + ++col; + }); + + while (col < i) { + handle(i, col, getZero()); + ++col; + } + } +} + +template +inline void NetworKit::DynamicMatrix::forNonZeroElementsInRowOrder(L handle) const { + for (index i = 0; i < nRows; ++i) { + graph.forEdgesOf(i, [&](index j, edgeweight weight) { handle(i, j, weight); }); + } +} + +template +inline void NetworKit::DynamicMatrix::parallelForNonZeroElementsInRowOrder(L handle) const { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(nRows); ++i) { + graph.forEdgesOf(i, [&](index j, edgeweight weight) { handle(i, j, weight); }); + } +} + +// print functions for test debugging / output +inline std::ostream &operator<<(std::ostream &os, const DynamicMatrix &M) { + for (index row = 0; row < M.numberOfRows(); ++row) { + if (row != 0) + os << std::endl; + for (index col = 0; col < M.numberOfColumns(); ++col) { + if (col != 0) + os << ", "; + os << M(row, col); + } + } + return os; +} +} // namespace NetworKit + +#endif // NETWORKIT_ALGEBRAIC_DYNAMIC_MATRIX_HPP_ diff --git a/vendor/include/networkit/algebraic/GraphBLAS.hpp b/vendor/include/networkit/algebraic/GraphBLAS.hpp new file mode 100644 index 0000000..e973454 --- /dev/null +++ b/vendor/include/networkit/algebraic/GraphBLAS.hpp @@ -0,0 +1,323 @@ +/* + * GraphBLAS.hpp + * + * Created on: May 31, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_GRAPH_BLAS_HPP_ +#define NETWORKIT_ALGEBRAIC_GRAPH_BLAS_HPP_ + +#include +#include +#include +#include +#include + +/** + * @ingroup algebraic + * Implements the GraphBLAS interface. For more information visit https://graphblas.org. + */ +namespace GraphBLAS { + +// **************************************************** +// Operations +// **************************************************** + +/** + * Computes binOp(A(i,j), B(i,j)) for all i,j element-wise. Note that the dimensions of + * @a A and @a B must coincide and that the zero must be the same. + * @param A + * @param B + * @param binOp + * @return The resulting matrix. + */ +template +Matrix eWiseBinOp(const Matrix &A, const Matrix &B, L binOp) { + assert(A.numberOfRows() == B.numberOfRows() && A.numberOfColumns() == B.numberOfColumns()); + assert(A.getZero() == B.getZero() && A.getZero() == SemiRing::zero()); + + std::vector columnPointer(A.numberOfColumns(), -1); + std::vector Arow(A.numberOfColumns(), SemiRing::zero()); + std::vector Brow(A.numberOfColumns(), SemiRing::zero()); + + std::vector triplets; + + for (NetworKit::index i = 0; i < A.numberOfRows(); ++i) { + NetworKit::index listHead = 0; + NetworKit::count nnz = 0; + + // search for nonZeros in matrix A + A.forNonZeroElementsInRow(i, [&](NetworKit::index j, double value) { + Arow[j] = value; + + columnPointer[j] = listHead; + listHead = j; + nnz++; + }); + + // search for nonZeros in matrix B + B.forNonZeroElementsInRow(i, [&](NetworKit::index j, double value) { + Brow[j] = value; + + if (columnPointer[j] == -1) { // matrix A does not have a nonZero entry in column j + columnPointer[j] = listHead; + listHead = j; + nnz++; + } + }); + + // apply operator on the found nonZeros in A and B + for (NetworKit::count k = 0; k < nnz; ++k) { + double value = binOp(Arow[listHead], Brow[listHead]); + if (value != SemiRing::zero()) { + triplets.push_back({i, listHead, value}); + } + + NetworKit::index temp = listHead; + listHead = columnPointer[listHead]; + + // reset for next row + columnPointer[temp] = -1; + Arow[temp] = SemiRing::zero(); + Brow[temp] = SemiRing::zero(); + } + + nnz = 0; + } + + return Matrix(A.numberOfRows(), A.numberOfColumns(), triplets, A.getZero()); +} + +/** + * Computes the matrix-matrix multiplication of @a A and @a B. Note that + * A.numberOfColumns() must be equal to B.numberOfRows() and the zero elements + * must be the same. The default Semiring is the ArithmeticSemiring. + * @param A + * @param B + * @return The result of the multiplication A * B. + */ +template +Matrix MxM(const Matrix &A, const Matrix &B) { + assert(A.numberOfColumns() == B.numberOfRows()); + assert(A.getZero() == SemiRing::zero() && B.getZero() == SemiRing::zero()); + + std::vector triplets; + NetworKit::SparseAccumulator spa(B.numberOfRows()); + for (NetworKit::index i = 0; i < A.numberOfRows(); ++i) { + A.forNonZeroElementsInRow(i, [&](NetworKit::index k, double w1) { + B.forNonZeroElementsInRow(k, [&](NetworKit::index j, double w2) { + spa.scatter(SemiRing::mult(w1, w2), j, *SemiRing::add); + }); + }); + + spa.gather([&](NetworKit::index i, NetworKit::index j, double value) { + triplets.push_back({i, j, value}); + }); + + spa.increaseRow(); + } + + return Matrix(A.numberOfRows(), B.numberOfColumns(), triplets, A.getZero()); +} + +/** + * Computes the matrix-matrix multiplication of @a A and @a B and adds it to @a C where + * the add operation is that of the specified Semiring (i.e. C(i,j) = SemiRing::add(C(i,j), + * (A*B)(i,j))). The default Semiring is the ArithmeticSemiring. + * @param A + * @param B + * @param C + */ +template +void MxM(const Matrix &A, const Matrix &B, Matrix &C) { + assert(A.numberOfColumns() == B.numberOfRows() && A.numberOfRows() == C.numberOfRows() + && B.numberOfColumns() == C.numberOfColumns()); + assert(A.getZero() == SemiRing::zero() && B.getZero() == SemiRing::zero() + && C.getZero() == SemiRing::zero()); + + std::vector triplets; + NetworKit::SparseAccumulator spa(B.numberOfRows()); + for (NetworKit::index i = 0; i < A.numberOfRows(); ++i) { + A.forNonZeroElementsInRow(i, [&](NetworKit::index k, double w1) { + B.forNonZeroElementsInRow(k, [&](NetworKit::index j, double w2) { + spa.scatter(SemiRing::mult(w1, w2), j, *SemiRing::add); + }); + }); + + spa.gather([&](NetworKit::index i, NetworKit::index j, double value) { + triplets.push_back({i, j, value}); + }); + + spa.increaseRow(); + } + + Matrix temp(A.numberOfRows(), B.numberOfRows(), triplets, A.getZero()); + C = eWiseBinOp(C, temp, *SemiRing::add); +} + +/** + * Computes the matrix-matrix multiplication of @a A and @a B and adds it to @a C where + * the add operation is specified by the binary function @a accum (i.e. C(i,j) = accum(C(i,j), + * (A*B)(i,j))). The default Semiring is the ArithmeticSemiring. + * @param A + * @param B + * @param C + * @param accum + */ +template +void MxM(const Matrix &A, const Matrix &B, Matrix &C, F accum) { + assert(A.numberOfColumns() == B.numberOfRows() && A.numberOfRows() == C.numberOfRows() + && B.numberOfColumns() == C.numberOfColumns()); + assert(A.getZero() == SemiRing::zero() && B.getZero() == SemiRing::zero() + && C.getZero() == SemiRing::zero()); + + std::vector triplets; + NetworKit::SparseAccumulator spa(B.numberOfRows()); + for (NetworKit::index i = 0; i < A.numberOfRows(); ++i) { + A.forNonZeroElementsInRow(i, [&](NetworKit::index k, double w1) { + B.forNonZeroElementsInRow(k, [&](NetworKit::index j, double w2) { + spa.scatter(SemiRing::mult(w1, w2), j, *SemiRing::add); + }); + }); + + spa.gather([&](NetworKit::index i, NetworKit::index j, double value) { + triplets.push_back({i, j, value}); + }); + + spa.increaseRow(); + } + + Matrix temp(A.numberOfRows(), B.numberOfRows(), triplets, A.getZero()); + C = eWiseBinOp(C, temp, accum); +} + +/** + * Computes the matrix-vector product of matrix @a A and Vector @a v. The default Semiring is the + * ArithmeticSemiring. + * @param A + * @param v + */ +template +NetworKit::Vector MxV(const Matrix &A, const NetworKit::Vector &v) { + assert(!v.isTransposed()); + assert(A.numberOfColumns() == v.getDimension()); + assert(A.getZero() == SemiRing::zero()); + NetworKit::Vector result(A.numberOfRows(), A.getZero()); + + A.parallelForNonZeroElementsInRowOrder( + [&](NetworKit::index i, NetworKit::index j, double value) { + result[i] = SemiRing::add(result[i], SemiRing::mult(value, v[j])); + }); + + return result; +} + +/** + * Computes the matrix-vector product of matrix @a A and Vector @a v and adds it to @a c where the + * add operation is that of the specified Semiring (i.e. c[i] = SemiRing::add(c[i], (A*v)[i]). The + * default Semiring is the ArithmeticSemiring. + * @param A + * @param v + * @param c + */ +template +void MxV(const Matrix &A, const NetworKit::Vector &v, NetworKit::Vector &c) { + assert(!v.isTransposed()); + assert(A.numberOfColumns() == v.getDimension()); + assert(A.getZero() == SemiRing::zero()); + + A.parallelForNonZeroElementsInRowOrder( + [&](NetworKit::index i, NetworKit::index j, double value) { + c[i] = SemiRing::add(c[i], SemiRing::mult(value, v[j])); + }); +} + +/** + * Computes the matrix-vector product of matrix @a A and Vector @a v and adds it to @a c where the + * add operation is that of the specified binary function @a accum (i.e. c[i] = accum(c[i], + * (A*v)[i]). The default Semiring is the ArithmeticSemiring. + * @param A + * @param v + * @param c + */ +template +void MxV(const Matrix &A, const NetworKit::Vector &v, NetworKit::Vector &c, F accum) { + assert(!v.isTransposed()); + assert(A.numberOfColumns() == v.getDimension()); + assert(A.getZero() == SemiRing::zero()); + + A.parallelForNonZeroElementsInRowOrder( + [&](NetworKit::index i, NetworKit::index j, double value) { + c[i] = accum(c[i], SemiRing::mult(value, v[j])); + }); +} + +/** + * Computes SemiRing::add(A(i,j), B(i,j)) for all i,j element-wise and returns the resulting matrix. + * The default Semiring is the ArithmeticSemiring. + * @param A + * @param B + */ +template +Matrix eWiseAdd(const Matrix &A, const Matrix &B) { + return eWiseBinOp( + A, B, [](const double a, const double b) { return SemiRing::add(a, b); }); +} + +/** + * Computes SemiRing::mult(A(i,j), B(i,j)) for all i,j element-wise and returns the resulting + * matrix. The default Semiring is the ArithmeticSemiring. + * @param A + * @param B + * @return + */ +template +Matrix eWiseMult(const Matrix &A, const Matrix &B) { + return eWiseBinOp( + A, B, [](const double a, const double b) { return SemiRing::mult(a, b); }); +} + +/** + * Computes the row-reduction of the @a matrix and returns the result as a vector. That is, the + * elements of each row are summed up to form the respective entry in the result vector. The add + * operator is that of the specified Semiring. The default Semiring is the ArithmeticSemiring. + * @param matrix + */ +template +NetworKit::Vector rowReduce(const Matrix &matrix) { + assert(matrix.getZero() == SemiRing::zero()); + NetworKit::Vector rowReduction(matrix.numberOfRows(), 0.0); + +#pragma omp parallel for + for (NetworKit::omp_index i = 0; i < static_cast(matrix.numberOfRows()); + ++i) { + matrix.forNonZeroElementsInRow(i, [&](NetworKit::index, double value) { + rowReduction[i] = SemiRing::add(rowReduction[i], value); + }); + } + + return rowReduction; +} + +/** + * Computes the column-reduction of the @a matrix and returns the result as a Vector. That is, the + * elements of each column are summed up to form the respective entry in the result Vector. The add + * operator is that of the specified Semiring. The default Semiring is the ArithmeticSemiring. + * @param matrix + */ +template +NetworKit::Vector columnReduce(const Matrix &matrix) { + assert(matrix.getZero() == SemiRing::zero()); + NetworKit::Vector columnReduction(matrix.numberOfColumns(), 0.0); + + matrix.forNonZeroElementsInRowOrder([&](NetworKit::index, NetworKit::index j, double value) { + columnReduction[j] = SemiRing::add(columnReduction[j], value); + }); + + return columnReduction; +} + +} // namespace GraphBLAS + +#endif // NETWORKIT_ALGEBRAIC_GRAPH_BLAS_HPP_ diff --git a/vendor/include/networkit/algebraic/MatrixTools.hpp b/vendor/include/networkit/algebraic/MatrixTools.hpp new file mode 100644 index 0000000..421c68d --- /dev/null +++ b/vendor/include/networkit/algebraic/MatrixTools.hpp @@ -0,0 +1,156 @@ +/* + * MatrixTools.hpp + * + * Created on: May 31, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_MATRIX_TOOLS_HPP_ +#define NETWORKIT_ALGEBRAIC_MATRIX_TOOLS_HPP_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace MatrixTools { + +/** + * Checks if @a matrix is symmetric. + * @param matrix + * @return True if @a matrix is symmetric, otherwise false. + */ +template +bool isSymmetric(const Matrix &matrix) { + bool output = true; + matrix.forNonZeroElementsInRowOrder( + [&](NetworKit::index i, NetworKit::index j, NetworKit::edgeweight w) { + if (std::fabs(matrix(j, i) - w) > NetworKit::FLOAT_EPSILON) { + output = false; + return; + } + }); + return output; +} + +/** + * Checks if @a matrix is symmetric diagonally dominant (SDD). + * @param matrix + * @return True if @a matrix is SDD, false otherwise. + */ +template +bool isSDD(const Matrix &matrix) { + if (!isSymmetric(matrix)) { + return false; + } + + /* Criterion: a_ii >= \sum_{j != i} a_ij */ + std::vector row_sum(matrix.numberOfRows()); + matrix.parallelForNonZeroElementsInRowOrder( + [&](NetworKit::node i, NetworKit::node j, double value) { + if (i == j) { + row_sum[i] += value; + } else { + row_sum[i] -= std::fabs(value); + } + }); + + return std::all_of(row_sum.begin(), row_sum.end(), + [](double val) { return val > -NetworKit::FLOAT_EPSILON; }); +} + +/** + * Checks if @a matrix is a Laplacian matrix. + * @param matrix + * @return True if @a matrix is a Laplacian matrix, false otherwise. + */ +template +bool isLaplacian(const Matrix &matrix) { + if (!isSymmetric(matrix)) { + return false; + } + + /* Criterion: \forall_i \sum_j A_ij = 0 */ + std::vector row_sum(matrix.numberOfRows()); + std::atomic right_sign(true); + matrix.parallelForNonZeroElementsInRowOrder( + [&](NetworKit::node i, NetworKit::node j, double value) { + if (i != j && value > NetworKit::FLOAT_EPSILON) { + right_sign = false; + } + row_sum[i] += value; + }); + + return right_sign && std::all_of(row_sum.begin(), row_sum.end(), [](double val) { + return std::fabs(val) < NetworKit::FLOAT_EPSILON; + }); +} + +/** + * Computes a graph having the given @a laplacian. + * @param laplacian + * @return The graph having a Laplacian equal to @a laplacian. + */ +template +NetworKit::GraphW laplacianToGraph(const Matrix &laplacian) { + assert(isLaplacian(laplacian)); + NetworKit::GraphW G(std::max(laplacian.numberOfRows(), laplacian.numberOfColumns()), true, + false); + laplacian.forNonZeroElementsInRowOrder( + [&](NetworKit::node u, NetworKit::node v, NetworKit::edgeweight weight) { + if (u != v) { // exclude diagonal + if (u < v) { + G.addEdge(u, v, -weight); + } + } + }); + + return G; +} + +/** + * Interprets the @a matrix as adjacency matrix of a graph. If @a matrix is non-symmetric, the graph + * will be directed. + * @param matrix + * @return The graph having an adjacency matrix equal to @a matrix. + */ +template +NetworKit::GraphW matrixToGraph(const Matrix &matrix) { + bool directed = !isSymmetric(matrix); + NetworKit::GraphW G(std::max(matrix.numberOfRows(), matrix.numberOfColumns()), true, directed); + matrix.forNonZeroElementsInRowOrder( + [&](NetworKit::node u, NetworKit::node v, NetworKit::edgeweight weight) { + if (directed || u <= v) { + G.addEdge(u, v, weight); + } + }); + + return G; +} + +/** + * Converts the @a other matrix into a equivalent matrix of the template parametrized type. + * @param other The input Matrix. + * @return Matrix of type DenseMatrix, CSRMatrix or DynamicMatrix. + */ +template +ToMatrix matrixTo(const FromMatrix &other) { + int nRows = other.numberOfRows(); + int nCols = other.numberOfColumns(); + ToMatrix ResMat(nRows, nCols, other.getZero()); + + other.forNonZeroElementsInRowOrder( + [&ResMat](int i, int j, double val) { ResMat.setValue(i, j, val); }); + + return ResMat; +} + +} // namespace MatrixTools + +#endif // NETWORKIT_ALGEBRAIC_MATRIX_TOOLS_HPP_ diff --git a/vendor/include/networkit/algebraic/Semirings.hpp b/vendor/include/networkit/algebraic/Semirings.hpp new file mode 100644 index 0000000..c4026c9 --- /dev/null +++ b/vendor/include/networkit/algebraic/Semirings.hpp @@ -0,0 +1,171 @@ +/* + * Semirings.hpp + * + * Created on: May 31, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_SEMIRINGS_HPP_ +#define NETWORKIT_ALGEBRAIC_SEMIRINGS_HPP_ + +#include + +// ***************************************************** +// Semiring Definitions +// ***************************************************** + +/** + * @ingroup algebraic + * add: arithmetic add + * mult: arithmetic multiplication + * zero: 0 + * one: 1 + * codomain = (-infty, +infty) + */ +class ArithmeticSemiring final { +public: + ArithmeticSemiring() = default; + ~ArithmeticSemiring() = default; + + inline static double add(double a, double b) { return a + b; } + + inline static double mult(double a, double b) { return a * b; } + + inline static double zero() { return 0; }; + + inline static double one() { return 1; }; +}; + +/** + * @ingroup algebraic + * add: min + * mult: arithmetic add + * zero: +infty + * one: 0 + * codomain = (-infty, +infty] + */ +class MinPlusSemiring final { +public: + MinPlusSemiring() = default; + ~MinPlusSemiring() = default; + + inline static double add(double a, double b) { return std::min(a, b); } + + inline static double mult(double a, double b) { return a + b; } + + inline static double zero() { return std::numeric_limits::infinity(); }; + + inline static double one() { return 0; }; +}; + +/** + * @ingroup algebraic + * add: max + * mult: arithmetic add + * zero: -infty + * one: 0 + * codomain = [-infty, +infty) + */ +class MaxPlusSemiring final { +public: + MaxPlusSemiring() = default; + ~MaxPlusSemiring() = default; + + inline static double add(double a, double b) { return std::max(a, b); } + + inline static double mult(double a, double b) { return a + b; } + + inline static double zero() { return -std::numeric_limits::infinity(); }; + + inline static double one() { return 0; }; +}; + +/** + * @ingroup algebraic + * add: min + * mult: max + * zero: +infty + * one: -infty + * codomain = [-infty, +infty] + */ +class MinMaxSemiring final { +public: + MinMaxSemiring() = default; + ~MinMaxSemiring() = default; + + inline static double add(double a, double b) { return std::min(a, b); } + + inline static double mult(double a, double b) { return std::max(a, b); } + + inline static double zero() { return std::numeric_limits::infinity(); }; + + inline static double one() { return -std::numeric_limits::infinity(); }; +}; + +/** + * @ingroup algebraic + * add: max + * mult: min + * zero: -infty + * one: +infty + * codomain = [-infty, +infty] + */ +class MaxMinSemiring final { +public: + MaxMinSemiring() = default; + ~MaxMinSemiring() = default; + + inline static double add(double a, double b) { return std::max(a, b); } + + inline static double mult(double a, double b) { return std::min(a, b); } + + inline static double zero() { return -std::numeric_limits::infinity(); }; + + inline static double one() { return 0; }; +}; + +/** + * @ingroup algebraic + * add: logical or + * mult: logical and + * zero: 0 + * one: 1 + * codomain = [-infty, +infty] + */ +class IntLogicalSemiring final { +public: + IntLogicalSemiring() = default; + ~IntLogicalSemiring() = default; + + inline static double add(double a, double b) { return (int)a || (int)b; } + + inline static double mult(double a, double b) { return (int)a && (int)b; } + + inline static double zero() { return 0; }; + + inline static double one() { return 1; }; +}; + +/** + * @ingroup algebraic + * add: xor + * mult: bitwise and + * zero: 0 + * one: 1 + * codomain = [0, 1] + */ +class GaloisFieldSemiring final { +public: + GaloisFieldSemiring() = default; + ~GaloisFieldSemiring() = default; + + inline static double add(double a, double b) { return (int)a ^ (int)b; } + + inline static double mult(double a, double b) { return (int)a & (int)b; } + + inline static double zero() { return 0; }; + + inline static double one() { return 1; }; +}; + +#endif // NETWORKIT_ALGEBRAIC_SEMIRINGS_HPP_ diff --git a/vendor/include/networkit/algebraic/SparseAccumulator.hpp b/vendor/include/networkit/algebraic/SparseAccumulator.hpp new file mode 100644 index 0000000..c628c81 --- /dev/null +++ b/vendor/include/networkit/algebraic/SparseAccumulator.hpp @@ -0,0 +1,111 @@ +/* + * SparseAccumulator.hpp + * + * Created on: 14.05.2014 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_SPARSE_ACCUMULATOR_HPP_ +#define NETWORKIT_ALGEBRAIC_SPARSE_ACCUMULATOR_HPP_ + +#include +#include +#include + +#include + +namespace NetworKit { + +/** + * The SparseAccumulator class represents the sparse accumulator datastructure as described in + * Kepner, Jeremy, and John Gilbert, eds. Graph algorithms in the language of linear algebra. + * Vol. 22. SIAM, 2011. It is used as temporal storage for efficient computations on matrices. + */ +class SparseAccumulator final { +private: + /** row indicator used to avoid resetting the occupied vector */ + count row; + + /** dense vector of doubles which stores the computed values */ + std::vector values; // w + + /** dense vector of integers which stores whether a valid value is stored in values at each + * position */ + std::vector occupied; // b + + /** unordered list to store the position of valid values in values vector */ + std::vector indices; // LS + +public: + /** + * Constructs the SparseAccumulator with size @a size. + * @param size The size of the SparseAccumulator. + */ + SparseAccumulator(count size) : row(1), values(size), occupied(size, 0) {} + + /** + * Stores @a value at @a pos. If a valid value is already stored at @a pos then @value is added + * to that. + * @param value The value to store or add at @a pos in values. + * @param pos The position in values. + */ + void scatter(double value, index pos) { + if (occupied[pos] < row) { + values[pos] = value; + occupied[pos] = row; + indices.push_back(pos); + } else { + values[pos] += value; + } + } + + /** + * Stores @a value at @a pos. If a valid value is already stored at @a pos then we call the + * binary handle function with the stored value and the new @a value as arguments. + * @param value The value to store or add at @a pos in values. + * @param pos The position in values. + * @param handle (double, double) -> double + */ + template + void scatter(double value, index pos, L &handle) { + assert(pos < values.size()); + + if (occupied[pos] < row) { + values[pos] = value; + occupied[pos] = row; + indices.push_back(pos); + } else { + values[pos] = handle(values[pos], value); + } + } + + /** + * Calls @a handle for each non zero value of the current row. + * @note handle signature: handle(index row, index column, double value) + * @return The number of non zero values in the current row. + * + */ + template + count gather(L handle) { + count nonZeros = 0; + std::sort(indices.begin(), indices.end()); + for (index idx : indices) { + handle(row - 1, idx, values[idx]); + ++nonZeros; + } + + return nonZeros; + } + + /** + * Sets the SparseAccumulator to the next row which invalidates all currently stored data. + */ + void increaseRow() { + ++row; + indices.clear(); + } +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_ALGEBRAIC_SPARSE_ACCUMULATOR_HPP_ diff --git a/vendor/include/networkit/algebraic/Vector.hpp b/vendor/include/networkit/algebraic/Vector.hpp new file mode 100644 index 0000000..af8e168 --- /dev/null +++ b/vendor/include/networkit/algebraic/Vector.hpp @@ -0,0 +1,371 @@ +/* + * Vector.hpp + * + * Created on: 12.03.2014 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_VECTOR_HPP_ +#define NETWORKIT_ALGEBRAIC_VECTOR_HPP_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace NetworKit { + +// forward declaration of DynamicMatrix class +class DynamicMatrix; + +/** + * @ingroup algebraic + * The Vector class represents a basic vector with double coefficients. + */ +class Vector final { +private: + std::vector values; + bool transposed; + +public: + /** Default constructor */ + Vector(); + + /** + * Constructs the Vector with @a dimension elements with value @a initialValue. + * @param dimension The dimension of this vector. + * @param initialValue All coefficients will be initialized to @a initialValue. + * @param transpose Indicates whether this vector is transposed (row vector) or not (column + * vector). + */ + Vector(count dimension, double initialValue = 0, bool transpose = false); + + /** + * Constructs the Vector with the contents of @a values. + * @param values The values of this Vector. + * @param transpose Indicates whether this vector is transposed (row vector) or not (column + * vector). + */ + Vector(const std::vector &values, bool transpose = false); + + /** + * Constructs the Vector from the contents of the initializer list @a list. + * @param list The initializer list. + */ + Vector(const std::initializer_list &list); + + /** + * @return dimension of vector + */ + inline count getDimension() const { return values.size(); } + + /** + * A transposed vector is a row vector. + * @return True, if this vector is transposed, otherwise false. + */ + bool isTransposed() const; + + /** + * @return Transposed copy of this vector. + */ + Vector transpose() const; + + /** + * Calculates and returns the Euclidean length of this vector + * @return The Euclidean length of this vector. + */ + double length() const; + + /** + * Calculates and returns the arithmetic mean of this vector + * @return The arithmetic mean of this vector. + */ + double mean() const; + + /** + * Returns a reference to the element at index @a idx without checking the range of this vector. + * @param idx The index of the element. + * @return Reference to the element at index @a idx. + */ + inline double &operator[](index idx) { + assert(idx < values.size()); + return values[idx]; + } + + /** + * Assigns the given value to all the elements in the vector. + * + * @param val The value to be assigned. + */ + void fill(double val) { std::fill(values.begin(), values.end(), val); } + + /** + * Returns the element at index @a idx without checking the range of this vector. + * @a idx The index of the element. + * @return Constant reference to the element at index @a idx. + */ + inline double operator[](index idx) const { + assert(idx < values.size()); + return values[idx]; + } + + /** + * Returns a reference to the element at index @a idx. If @a idx is not a valid index an + * exception is thrown. + * @param idx The index of the element. + * @return Reference to the element at index @a idx. + */ + double &at(index idx) { + if (idx >= values.size()) { + throw std::runtime_error("index out of range"); + } else { + return values[idx]; + } + } + + /** + * Compares this vector and @a other element-wise. + * @return True, if this vector is element-wise equal to @a other, otherwise false. + */ + bool operator==(const Vector &other) const; + + /** + * Compares this vector and @a other element-wise. + * @return True, if this vector is element-wise unequal to @a other, otherwise false. + */ + bool operator!=(const Vector &other) const; + + /** + * Computes the outer product of @a v1 and @a v2. + * @param v1 First Vector. + * @param v2 Second Vector. + * @return The resulting matrix from the outer product. + */ + template + static Matrix outerProduct(const Vector &v1, const Vector &v2); + + /** + * Computes the inner product (dot product) of the vectors @a v1 and @a v2. + * @return The result of the inner product. + */ + static double innerProduct(const Vector &v1, const Vector &v2); + + /** + * Computes the inner product (dot product) of this vector and @a other. + * @return The result of the inner product. + */ + double operator*(const Vector &other) const; + + /** + * Multiplies this vector with @a matrix and returns the result. + * @return The result of multiplying this vector with @a matrix. + */ + template + Vector operator*(const Matrix &matrix) const; + + /** + * Multiplies this vector with a scalar specified in @a scalar and returns the result in a new + * vector. + * @return The result of multiplying this vector with @a scalar. + */ + Vector operator*(double scalar) const; + + /* + * Multiplies this vector with a scalar specified in @a scalar. + * @return Reference to this vector. + */ + Vector &operator*=(double scalar); + + /** + * Divides this vector by a divisor specified in @a divisor and returns the result in a new + * vector. + * @return The result of dividing this vector by @a divisor. + */ + Vector operator/(double divisor) const; + + /** + * Divides this vector by a divisor specified in @a divisor. + * @return Reference to this vector. + */ + Vector &operator/=(double divisor); + + /** + * Adds this vector to @a other and returns the result. + * Note that the dimensions of the vectors have to be the same. + * @return The sum of this vector and @a other. + */ + Vector operator+(const Vector &other) const; + + /** + * Adds @a value to each element of this vector and returns the result. + */ + Vector operator+(double value) const; + + /** + * Adds @a other to this vector. + * Note that the dimensions of the vectors have to be the same. + * @return Reference to this vector. + */ + Vector &operator+=(const Vector &other); + + /** + * Adds @a value to each element of this vector. + */ + Vector &operator+=(double value); + + /** + * Subtracts @a other from this vector and returns the result. + * Note that the dimensions of the vectors have to be the same. + * @return The difference of this vector and @a other. + * + */ + Vector operator-(const Vector &other) const; + + /** + * Subtracts @a value from each element of this vector and returns the result. + */ + Vector operator-(double value) const; + + /** + * Subtracts @a other from this vector. + * Note that the dimensions of the vectors have to be the same. + * @return Reference to this vector. + */ + Vector &operator-=(const Vector &other); + + /** + * Subtracts @a value from each element of this vector. + */ + Vector &operator-=(double value); + + /** + * Applies the unary function @a unaryElementFunction to each value in the Vector. Note that it + * must hold that the function applied to the zero element of this matrix returns the zero + * element. + * @param unaryElementFunction + */ + template + void apply(F unaryElementFunction); + + /** + * Iterate over all elements of the vector and call handler (lambda closure). + */ + template + void forElements(L handle); + + /** + * Iterate over all elements of the vector and call handler (lambda closure). + */ + template + void forElements(L handle) const; + + /** + * Iterate in parallel over all elements of the vector and call handler (lambda closure). + * + */ + template + void parallelForElements(L handle); + + /** + * Iterate in parallel over all elements of the vector and call handler (lambda closure). + */ + template + void parallelForElements(L handle) const; +}; + +/** + * Multiplies the vector @a v with a scalar specified in @a scalar and returns the result. + * @return The result of multiplying this vector with @a scalar. + */ +inline Vector operator*(double scalar, const Vector &v) { + return v.operator*(scalar); +} + +template +Matrix Vector::outerProduct(const Vector &v1, const Vector &v2) { + std::vector triplets; + + for (index i = 0; i < v1.getDimension(); ++i) { + for (index j = 0; j < v2.getDimension(); ++j) { + double result = v1[i] * v2[j]; + if (std::fabs(result) >= FLOAT_EPSILON) { + triplets.push_back({i, j, result}); + } + } + } + + return Matrix(v1.getDimension(), v2.getDimension(), triplets); +} + +template +Vector Vector::operator*(const Matrix &matrix) const { + assert(isTransposed()); // vector must be of the form 1xn + assert(getDimension() == matrix.numberOfRows()); // dimensions of vector and matrix must match + + Vector result(matrix.numberOfColumns(), 0.0, true); +#pragma omp parallel for + for (omp_index k = 0; k < static_cast(matrix.numberOfColumns()); ++k) { + Vector column = matrix.column(k); + result[k] = (*this) * column; + } + + return result; +} + +template +void Vector::apply(F unaryElementFunction) { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(getDimension()); ++i) { + values[i] = unaryElementFunction(values[i]); + } +} + +template +inline void Vector::forElements(L handle) { + for (uint64_t i = 0; i < getDimension(); ++i) { + handle(values[i]); + } +} + +template +inline void Vector::forElements(L handle) const { + for (uint64_t i = 0; i < getDimension(); ++i) { + handle(values[i]); + } +} + +template +inline void Vector::parallelForElements(L handle) { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(getDimension()); ++i) { + handle(i, values[i]); + } +} + +template +inline void Vector::parallelForElements(L handle) const { +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(getDimension()); ++i) { + handle(i, values[i]); + } +} + +// print functions for test debugging / output. Prints Vector as [0, 1, 2, 3, 4] +inline std::ostream &operator<<(std::ostream &os, const Vector &vec) { + os << "["; + for (index i = 0; i < vec.getDimension(); i++) { + if (i != 0) + os << ", "; + os << vec[i]; + } + os << "]"; + return os; +} + +} /* namespace NetworKit */ +#endif // NETWORKIT_ALGEBRAIC_VECTOR_HPP_ diff --git a/vendor/include/networkit/algebraic/algorithms/AlgebraicBFS.hpp b/vendor/include/networkit/algebraic/algorithms/AlgebraicBFS.hpp new file mode 100644 index 0000000..a5f4f56 --- /dev/null +++ b/vendor/include/networkit/algebraic/algorithms/AlgebraicBFS.hpp @@ -0,0 +1,72 @@ +/* + * AlgebraicBFS.hpp + * + * Created on: Jun 7, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_BFS_HPP_ +#define NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_BFS_HPP_ + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * Implementation of Breadth-First-Search using the GraphBLAS interface. + */ +template +class AlgebraicBFS : public Algorithm { +public: + /** + * Constructs an instance of the AlgebraicBFS algorithm for the given Graph @a graph and the + * given @a source node. + * @param graph + * @param source + */ + AlgebraicBFS(const Graph &graph, node source) + : At(Matrix::adjacencyMatrix(graph, MinPlusSemiring::zero()).transpose()), source(source) {} + + /** + * Runs a bfs using the GraphBLAS interface from the source node. + */ + void run(); + + /** + * Returns the distance from the source to node @a v. + * @param v + */ + double distance(node v) const { + assureFinished(); + assert(v <= At.numberOfRows()); + return distances[v]; + } + +private: + Matrix At; + node source; + Vector distances; +}; + +template +void AlgebraicBFS::run() { + count n = At.numberOfRows(); + distances = Vector(n, std::numeric_limits::infinity()); + distances[source] = 0; + + Vector oldDist; + do { + oldDist = distances; + GraphBLAS::MxV(At, distances, distances); + } while (oldDist != distances); + + hasRun = true; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_BFS_HPP_ diff --git a/vendor/include/networkit/algebraic/algorithms/AlgebraicBellmanFord.hpp b/vendor/include/networkit/algebraic/algorithms/AlgebraicBellmanFord.hpp new file mode 100644 index 0000000..121d84d --- /dev/null +++ b/vendor/include/networkit/algebraic/algorithms/AlgebraicBellmanFord.hpp @@ -0,0 +1,88 @@ +/* + * AlgebraicBellmanFord.hpp + * + * Created on: Jun 6, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_BELLMAN_FORD_HPP_ +#define NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_BELLMAN_FORD_HPP_ + +#include + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * Implementation of the Bellman-Ford algorithm using the GraphBLAS interface. + */ +template +class AlgebraicBellmanFord : public Algorithm { +public: + /** + * Construct an instance of the BellmanFord algorithm for the Graph @a graph and the given @a + * source node. + * @param graph + * @param source + */ + AlgebraicBellmanFord(const Graph &graph, node source) + : At(Matrix::adjacencyMatrix(graph, MinPlusSemiring::zero()).transpose()), source(source), + negCycle(false) {} + + /** Default destructor */ + ~AlgebraicBellmanFord() = default; + + /** + * Compute the shortest path from the source to all other nodes. + */ + void run(); + + /** + * Returns the distance from the source node to @a t. + * @param t Target node. + * @return The distance from source to target node @a t. + */ + inline edgeweight distance(node t) const { + assert(t < At.numberOfRows()); + assureFinished(); + return distances[t]; + } + + /** + * @return True if there is a negative cycle present in the graph, otherwise false. + */ + inline bool hasNegativeCycle() const { + assureFinished(); + return negCycle; + } + +private: + const Matrix At; + node source; + Vector distances; + bool negCycle; +}; + +template +void AlgebraicBellmanFord::run() { + count n = At.numberOfRows(); + distances = Vector(n, std::numeric_limits::infinity()); + distances[source] = 0; + + for (index k = 1; k < n; ++k) { + GraphBLAS::MxV(At, distances, distances); + } + + Vector oldDist = distances; + GraphBLAS::MxV(At, distances, distances); + negCycle = (oldDist != distances); + hasRun = true; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_BELLMAN_FORD_HPP_ diff --git a/vendor/include/networkit/algebraic/algorithms/AlgebraicMatchingCoarsening.hpp b/vendor/include/networkit/algebraic/algorithms/AlgebraicMatchingCoarsening.hpp new file mode 100644 index 0000000..2319f5b --- /dev/null +++ b/vendor/include/networkit/algebraic/algorithms/AlgebraicMatchingCoarsening.hpp @@ -0,0 +1,96 @@ +/* + * AlgebraicMatchingCoarsening.hpp + * + * Created on: Jul 12, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_MATCHING_COARSENING_HPP_ +#define NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_MATCHING_COARSENING_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * Implements an algebraic version of the MatchingCoarsening algorithm by computing a projection + * matrix from fine to coarse. + */ +template +class AlgebraicMatchingCoarsening final : public GraphCoarsening { +public: + /** + * Constructs an instance of AlgebraicMatchingCoarsening for the given Graph @a graph and the + * corresponding Matching @a matching. If @a noSelfLoops is set to true (false by default), no + * self-loops are created during the coarsening. + * @param graph + * @param matching + * @param noSelfLoops + */ + AlgebraicMatchingCoarsening(const Graph &graph, const Matching &matching, + bool noSelfLoops = false); + + /** + * Computes the coarsening for the graph using the given matching. + */ + void run() override; + +private: + Matrix A; // adjacency matrix of the graph + Matrix P; // projection matrix + bool noSelfLoops; +}; + +template +AlgebraicMatchingCoarsening::AlgebraicMatchingCoarsening(const Graph &graph, + const Matching &matching, + bool noSelfLoops) + : GraphCoarsening(graph), A(Matrix::adjacencyMatrix(graph)), noSelfLoops(noSelfLoops) { + if (G->isDirected()) + throw std::runtime_error("Only defined for undirected graphs."); + nodeMapping.resize(graph.numberOfNodes()); + std::vector triplets(graph.numberOfNodes()); + + count numCoarse = graph.numberOfNodes() - matching.size(graph); + index idx = 0; + graph.forNodes([&](node u) { + index mate = matching.mate(u); + if ((mate == none) || (u < mate)) { + // vertex u is carried over to the new level + nodeMapping[u] = idx; + ++idx; + } else { + // vertex u is not carried over, receives ID of mate + nodeMapping[u] = nodeMapping[mate]; + } + + triplets[u] = {u, nodeMapping[u], 1}; + }); + + P = Matrix(graph.numberOfNodes(), numCoarse, triplets); // dimensions: fine x coarse +} + +template +void AlgebraicMatchingCoarsening::run() { + Matrix coarseAdj = + P.transpose() * A + * P; // Matrix::mTmMultiply performs worse due to high sparsity of P (nnz = n) + + Gcoarsened = GraphW(coarseAdj.numberOfRows(), true); + coarseAdj.forNonZeroElementsInRowOrder([&](node u, node v, edgeweight weight) { + if (u == v && !noSelfLoops) { + Gcoarsened.addEdge(u, v, weight / 2.0); + } else if (u < v) { + Gcoarsened.addEdge(u, v, weight); + } + }); + + hasRun = true; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_MATCHING_COARSENING_HPP_ diff --git a/vendor/include/networkit/algebraic/algorithms/AlgebraicPageRank.hpp b/vendor/include/networkit/algebraic/algorithms/AlgebraicPageRank.hpp new file mode 100644 index 0000000..63c3a11 --- /dev/null +++ b/vendor/include/networkit/algebraic/algorithms/AlgebraicPageRank.hpp @@ -0,0 +1,145 @@ +/* + * AlgebraicPageRank.hpp + * + * Created on: Jun 20, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_PAGE_RANK_HPP_ +#define NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_PAGE_RANK_HPP_ + +#include +#include + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * Implementation of PageRank using the GraphBLAS interface. + */ +template +class AlgebraicPageRank final : public Centrality { +public: + /** + * Constructs an instance of AlgebraicPageRank for the given @a graph. Page rank uses the + * damping factor @a damp and the tolerance @a tol. + * @param graph + * @param damp + * @param tol + */ + AlgebraicPageRank(const Graph &graph, const double damp = 0.85, const double tol = 1e-8) + : Centrality(graph), damp(damp), tol(tol) { + Matrix A = Matrix::adjacencyMatrix(graph); + // normalize At by out-degree + Vector invOutDeg = GraphBLAS::rowReduce(A); +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(invOutDeg.getDimension()); ++i) { + invOutDeg[i] = 1.0 / invOutDeg[i]; + } + + std::vector mTriplets(A.nnz()); + index idx = 0; + A.forNonZeroElementsInRowOrder([&](index i, index j, double value) { + mTriplets[idx++] = {j, i, damp * value * invOutDeg[i]}; + }); + M = std::move(Matrix(A.numberOfRows(), mTriplets)); + } + + void run() override; + + /** + * Get a vector containing the betweenness score for each node in the graph. + * + * @return The betweenness scores calculated by @ref run(). + */ + const std::vector &scores() const override; + + /** + * Get a vector of pairs sorted into descending order. Each pair contains a node and the + * corresponding score calculated by @ref run(). + * @return A vector of pairs. + */ + std::vector> ranking() override; + + /** + * Get the betweenness score of node @a v calculated by @ref run(). + * + * @param v A node. + * @return The betweenness score of node @a v. + */ + double score(node v) override; + + /** + * Get the theoretical maximum of centrality score in the given graph. + * + * @return The maximum centrality score. + */ + double maximum() override { return 1.0; } + +private: + Matrix M; + + const double damp; + const double tol; +}; + +template +void AlgebraicPageRank::run() { + count n = M.numberOfRows(); + double teleportProb = (1.0 - damp) / (double)n; + Vector rank(n, 1.0 / (double)n); + Vector lastRank; + + do { + lastRank = rank; + rank = M * rank; + rank.apply([&](double value) { return value += teleportProb; }); + } while ((rank - lastRank).length() > tol); + + double sum = 0.0; +#pragma omp parallel for reduction(+ : sum) + for (omp_index i = 0; i < static_cast(rank.getDimension()); ++i) { + sum += rank[i]; + } + + scoreData.resize(n, 0); +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(rank.getDimension()); ++i) { + scoreData[i] = rank[i] / sum; + } + + hasRun = true; +} + +template +const std::vector &AlgebraicPageRank::scores() const { + assureFinished(); + return scoreData; +} + +template +std::vector> AlgebraicPageRank::ranking() { + assureFinished(); + std::vector> ranking; + for (index i = 0; i < scoreData.size(); ++i) { + ranking.push_back({i, scoreData[i]}); + } + Aux::Parallel::sort( + ranking.begin(), ranking.end(), + [](std::pair x, std::pair y) { return x.second > y.second; }); + return ranking; +} + +template +double AlgebraicPageRank::score(node v) { + assureFinished(); + return scoreData.at(v); +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_PAGE_RANK_HPP_ diff --git a/vendor/include/networkit/algebraic/algorithms/AlgebraicSpanningEdgeCentrality.hpp b/vendor/include/networkit/algebraic/algorithms/AlgebraicSpanningEdgeCentrality.hpp new file mode 100644 index 0000000..e93654f --- /dev/null +++ b/vendor/include/networkit/algebraic/algorithms/AlgebraicSpanningEdgeCentrality.hpp @@ -0,0 +1,122 @@ +/* + * AlgebraicSpanningEdgeCentrality.hpp + * + * Created on: Jul 12, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_SPANNING_EDGE_CENTRALITY_HPP_ +#define NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_SPANNING_EDGE_CENTRALITY_HPP_ + +#include +#include + +#include +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * Implementation of Spanning edge centrality with algebraic notation. + */ +template +class AlgebraicSpanningEdgeCentrality : public Centrality { +public: + /** + * Constructs an instance of the AlgebraicSpanningEdgeCentrality algorithm for the given Graph + * @a graph. The tolerance @a tol is used to control the approximation error when approximating + * the spanning edge centrality for @a graph. + * @param graph + * @param tol + */ + AlgebraicSpanningEdgeCentrality(const Graph &graph, double tol = 0.1) + : Centrality(graph), tol(tol) {} + + /** + * Compute spanning edge centrality exactly. + */ + void run() override; + + /** + * Approximate spanning edge centrality scores with the Johnson-Lindenstrauss transform. + */ + void runApproximation(); + +private: + double tol; +}; + +template +void AlgebraicSpanningEdgeCentrality::run() { + const count n = G.numberOfNodes(); + const count m = G.numberOfEdges(); + scoreData.clear(); + scoreData.resize(m, 0.0); + + std::vector rhs(m, Vector(n)); + this->G.parallelForEdges([&](node u, node v, edgeid e) { + rhs[e][u] = +1; + rhs[e][v] = -1; + }); + + std::vector solutions(m, Vector(n)); + + Lamg lamg(1e-5); + lamg.setupConnected(Matrix::laplacianMatrix(this->G)); + lamg.parallelSolve(rhs, solutions); + + this->G.parallelForEdges([&](node u, node v, edgeid e) { + double diff = solutions[e][u] - solutions[e][v]; + scoreData[e] = std::fabs(diff); + }); + + hasRun = true; +} + +template +void AlgebraicSpanningEdgeCentrality::runApproximation() { + const count n = G.numberOfNodes(); + const count m = G.numberOfEdges(); + scoreData.clear(); + scoreData.resize(m, 0.0); + double epsilon2 = tol * tol; + const count k = std::ceil(std::log2(n)) / epsilon2; + double randTab[2] = {1.0 / std::sqrt(k), -1.0 / std::sqrt(k)}; + + const auto rhsLoader = [&](count, Vector &yRow) -> Vector & { + yRow.fill(0); + G.forEdges([&](node u, node v, edgeweight w, index) { + double rand = randTab[Aux::Random::integer(1)]; + yRow[u] += w * rand; + yRow[v] -= w * rand; + }); + return yRow; + }; + + std::vector> scoreDataAtom(m); + const auto resultProcessor = [&](count, const Vector &zRow) { + G.forEdges([&](node u, node v, edgeid e) { + double diff = (zRow[u] - zRow[v]); + diff *= diff; + for (double old = scoreDataAtom[e].load(); !scoreDataAtom[e].compare_exchange_strong( + old, old + diff, std::memory_order_relaxed);) + ; + }); + }; + + Lamg lamg(1e-5); + lamg.setupConnected(Matrix::laplacianMatrix(this->G)); + lamg.parallelSolve(rhsLoader, resultProcessor, std::make_pair(k, n)); + +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(m); ++i) { + scoreData[i] = scoreDataAtom[i].load(std::memory_order_relaxed); + } + + hasRun = true; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_SPANNING_EDGE_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/algebraic/algorithms/AlgebraicTriangleCounting.hpp b/vendor/include/networkit/algebraic/algorithms/AlgebraicTriangleCounting.hpp new file mode 100644 index 0000000..6c66ef5 --- /dev/null +++ b/vendor/include/networkit/algebraic/algorithms/AlgebraicTriangleCounting.hpp @@ -0,0 +1,76 @@ +/* + * AlgebraicTriangleCounting.hpp + * + * Created on: Jul 12, 2016 + * Author: Michael Wegner (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_TRIANGLE_COUNTING_HPP_ +#define NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_TRIANGLE_COUNTING_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup algebraic + * Implements a triangle counting algorithm for nodes based on algebraic methods. + */ +template +class AlgebraicTriangleCounting : public Algorithm { +public: + /** + * Creates an instance of AlgebraicTriangleCounting for the given Graph @a graph. + * @param graph + */ + AlgebraicTriangleCounting(const Graph &graph) + : A(Matrix::adjacencyMatrix(graph)), directed(graph.isDirected()) {} + + /** + * Computes the number of triangles each node is part of. A triangle is considered as a set of + * nodes (i.e. if there is a triangle (u,v,w) it only counts as one triangle at each node). + */ + void run() override; + + /** + * Returns the score of node @a u. + * @param u + */ + count score(node u) const { + assureFinished(); + assert(u < A.numberOfRows()); + return nodeScores[u]; + } + + /** + * Returns the scores for all nodes of the graph. + */ + const std::vector &getScores() const { + assureFinished(); + return nodeScores; + } + +private: + Matrix A; + bool directed; + std::vector nodeScores; +}; + +template +void AlgebraicTriangleCounting::run() { + Matrix powA = A * A * A; + + nodeScores.clear(); + nodeScores.resize(A.numberOfRows(), 0); + +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(powA.numberOfRows()); ++i) { + nodeScores[i] = directed ? powA(i, i) : powA(i, i) / 2.0; + } + + hasRun = true; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_ALGEBRAIC_ALGORITHMS_ALGEBRAIC_TRIANGLE_COUNTING_HPP_ diff --git a/vendor/include/networkit/auxiliary/AlignedAllocator.hpp b/vendor/include/networkit/auxiliary/AlignedAllocator.hpp new file mode 100644 index 0000000..d23f201 --- /dev/null +++ b/vendor/include/networkit/auxiliary/AlignedAllocator.hpp @@ -0,0 +1,113 @@ + +#ifndef NETWORKIT_AUXILIARY_ALIGNED_ALLOCATOR_HPP_ +#define NETWORKIT_AUXILIARY_ALIGNED_ALLOCATOR_HPP_ + +#include + +/** + * Allocator for aligned data. + * + * Modified from the Mallocator from Stephan T. Lavavej. + * + */ +template +class AlignedAllocator { +public: + // The following will be the same for virtually all allocators. + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + T *address(T &r) const { return &r; } + + const T *address(const T &s) const { return &s; } + + size_t max_size() const { + // The following has been carefully written to be independent of + // the definition of size_t and to avoid signed/unsigned warnings. + return (static_cast(0) - static_cast(1)) / sizeof(T); + } + + // The following must be the same for all allocators. + template + struct rebind { + typedef AlignedAllocator other; + }; + + bool operator!=(const AlignedAllocator &other) const { return !(*this == other); } + + void construct(T *const p, const T &t) const { + void *const pv = static_cast(p); + + new (pv) T(t); + } + + void destroy(T *const p) const { p->~T(); } + + // Returns true if and only if storage allocated from *this + // can be deallocated from other, and vice versa. + // Always returns true for stateless allocators. + bool operator==(const AlignedAllocator &) const { return true; } + + // Default constructor, copy constructor, rebinding constructor, and destructor. + // Empty for stateless allocators. + AlignedAllocator() {} + + AlignedAllocator(const AlignedAllocator &) {} + + template + AlignedAllocator(const AlignedAllocator &) {} + + ~AlignedAllocator() {} + + // The following will be different for each allocator. + T *allocate(size_t n) const { + // The return value of allocate(0) is unspecified. + // Mallocator returns NULL in order to avoid depending + // on malloc(0)'s implementation-defined behavior + // (the implementation can define malloc(0) to return NULL, + // in which case the bad_alloc check below would fire). + // All allocators can return NULL in this case. + if (n == 0) + return NULL; + + // All allocators should contain an integer overflow check. + // The Standardization Committee recommends that std::length_error + // be thrown in the case of integer overflow. + if (n > max_size()) + throw std::length_error("AlignedAllocator::allocate() - Integer overflow."); + + // Mallocator wraps malloc(). + void *const pv = _mm_malloc(n * sizeof(T), Alignment); + + // Allocators should throw std::bad_alloc in the case of memory allocation failure. + if (pv == NULL) + throw std::bad_alloc(); + + return static_cast(pv); + } + + void deallocate(T *const p, size_t) const { _mm_free(p); } + + // The following will be the same for all allocators that ignore hints. + template + T *allocate(size_t n, const U * /* const hint */) const { + return allocate(n); + } + + // Allocators are not required to be assignable, so + // all allocators should have a private unimplemented + // assignment operator. Note that this will trigger the + // off-by-default (enabled under /Wall) warning C4626 + // "assignment operator could not be generated because a + // base class assignment operator is inaccessible" within + // the STL headers, but that warning is useless. +private: + AlignedAllocator &operator=(const AlignedAllocator &); +}; + +#endif // NETWORKIT_AUXILIARY_ALIGNED_ALLOCATOR_HPP_ diff --git a/vendor/include/networkit/auxiliary/ArrayTools.hpp b/vendor/include/networkit/auxiliary/ArrayTools.hpp new file mode 100644 index 0000000..78ef306 --- /dev/null +++ b/vendor/include/networkit/auxiliary/ArrayTools.hpp @@ -0,0 +1,85 @@ +#ifndef NETWORKIT_AUXILIARY_ARRAY_TOOLS_HPP_ +#define NETWORKIT_AUXILIARY_ARRAY_TOOLS_HPP_ + +#include +#include +#include + +#include + +#include + +namespace Aux { +namespace ArrayTools { + +template +void applyPermutation(ArrayIt first, ArrayIt last, PermIt permFirst) { + + using PermType = typename std::iterator_traits::value_type; + static_assert(std::is_integral::value, "Elements of permutation must be integral."); + + const size_t arraySize = + static_cast::difference_type>(last - first); + + const size_t usedBitsInPerm = tlx::integer_log2_ceil(arraySize); + // Avoid to use the sign bit if signed integral + const size_t bitsInPerm = sizeof(PermType) * 8 - (std::is_signed::value ? 1 : 0); + + if (bitsInPerm == usedBitsInPerm) { + // All bits in permutation are needed, we mark swapped elements with a bool vector + std::vector swapped(arraySize); + for (size_t i = 0; i < arraySize; ++i) { + if (swapped[i]) + continue; + + size_t cur = i; + swapped[cur] = true; + auto tmp = std::move(first[cur]); + + while (static_cast(permFirst[cur]) != i) { + first[cur] = std::move(first[permFirst[cur]]); + cur = permFirst[cur]; + swapped[cur] = true; + } + + first[cur] = std::move(tmp); + } + } else { + // Not all bits in the permutation are needed, we use the last (or, if signed integral, + // second to last) bit in the permutation to mark swapped elements + const auto mask = PermType{1} << (bitsInPerm - (std::is_signed::value ? 2 : 1)); + + const auto swapped = [&permFirst, mask = mask](size_t i) -> bool { + return (permFirst[i] & mask) != 0; + }; + + const auto markSwapped = [&permFirst, mask = mask](size_t i) -> void { + permFirst[i] |= mask; + }; + + for (size_t i = 0; i < arraySize; ++i) { + if (swapped(i)) + continue; + + size_t cur = i; + markSwapped(cur); + auto tmp = std::move(first[cur]); + + while (static_cast(permFirst[cur] & ~mask) != i) { + first[cur] = std::move(first[permFirst[cur] & ~mask]); + cur = permFirst[cur] & ~mask; + markSwapped(cur); + } + + first[cur] = std::move(tmp); + } + + for (size_t i = 0; i < arraySize; ++i) + permFirst[i] &= ~mask; + } +} + +} // namespace ArrayTools +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_ARRAY_TOOLS_HPP_ diff --git a/vendor/include/networkit/auxiliary/BloomFilter.hpp b/vendor/include/networkit/auxiliary/BloomFilter.hpp new file mode 100644 index 0000000..48ac9e9 --- /dev/null +++ b/vendor/include/networkit/auxiliary/BloomFilter.hpp @@ -0,0 +1,70 @@ +/* + * BloomFilter.hpp + * + * Created on: 08.08.2015 + * Author: Henning + */ + +#ifndef NETWORKIT_AUXILIARY_BLOOM_FILTER_HPP_ +#define NETWORKIT_AUXILIARY_BLOOM_FILTER_HPP_ + +#include + +#include +#include + +namespace Aux { + +using index = NetworKit::index; +using count = NetworKit::count; + +/** + * Bloom filter for fast set membership queries for type index with one-sided error (false + * positives). Uses one hash function instead of many but different random salts instead. + */ +class BloomFilter { +private: + count numHashes; + count size; + std::vector> membership; + std::vector salts; + + /** + * Hashes @a key with the salt at index @a hfunc (to mimic a different hash function). + * @param[in] key Key to be hashed. + * @param[in] hfunc In principle index of a hash function, here index of a salt. + * @return Hash value of salted key. + */ + index hash(index key, index hfunc) const; + +public: + /** + * Constructor. Space complexity: @a numHashes * @a size bytes. + * @param[in] numHashes Number of different hash functions that should be used. + * Actually, the implementation uses @a numHashes different random salts instead and one + * hash function only. + * @param[in] size Size of each hash array. + */ + BloomFilter(count numHashes, count size = 6291469); + + /** + * Destructor. + */ + virtual ~BloomFilter() = default; + + /** + * Inserts @a key into Bloom filter. + * @param[in] key Key to be inserted. + */ + void insert(index key); + + /** + * @param[in] key Key to be queried for set membership. + * @return True if @a is member, false otherwise. + */ + bool isMember(index key) const; +}; + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_BLOOM_FILTER_HPP_ diff --git a/vendor/include/networkit/auxiliary/BucketPQ.hpp b/vendor/include/networkit/auxiliary/BucketPQ.hpp new file mode 100644 index 0000000..dce2279 --- /dev/null +++ b/vendor/include/networkit/auxiliary/BucketPQ.hpp @@ -0,0 +1,142 @@ +/* + * BucketPQ.hpp + * + * Created on: 02.03.2017 + * Author: Henning + */ + +#ifndef NETWORKIT_AUXILIARY_BUCKET_PQ_HPP_ +#define NETWORKIT_AUXILIARY_BUCKET_PQ_HPP_ + +#include +#include + +#include +#include + +namespace Aux { + +using index = NetworKit::index; +using count = NetworKit::count; +using Bucket = std::list; +constexpr int64_t none = std::numeric_limits::max(); + +/** + * Addressable priority queue for values in the range [0,n) and + * integer keys (= priorities) in the range [minPrio, maxPrio]. + * minPrio and maxPrio can be positive or negative, respectively with + * the obvious constraint minPrio <= maxPrio. + * Amortized constant running time for each operation. + */ +class BucketPQ : public PrioQueue { +private: + std::vector buckets; // the actual buckets + static Bucket dummyBucket; + static const Bucket::iterator invalidPtr; + + struct OptionalIterator { + bool valid; + Bucket::iterator iter; + + void reset() { + valid = false; + iter = invalidPtr; + } + OptionalIterator() { reset(); } + OptionalIterator(bool valid, Bucket::iterator iter) : valid(valid), iter(iter) {} + }; + + std::vector nodePtr; // keeps track of node positions + std::vector myBucket; // keeps track of current bucket for each value + int64_t currentMinKey; // current min key + int64_t currentMaxKey; // current max key + int64_t minAdmissibleKey; // minimum admissible key + int64_t maxAdmissibleKey; // maximum admissible key + count numElems; // number of elements stored + int64_t offset; // offset from minAdmissibleKeys to 0 + + /** + * Constructor. Not to be used, only here for overriding. + */ + BucketPQ(const std::vector &) {} + + /** + * Constructor. Not to be used, only here for overriding. + */ + BucketPQ(uint64_t) {} + + /** + * Called from various constructors for initializing members. + */ + void construct(uint64_t capacity); + +public: + /** + * Builds priority queue from the vector @a keys, values are indices + * of @a keys. + * @param[in] keys Vector of keys + * @param[in] minAdmissibleKey Minimum admissible key + * @param[in] maxAdmissibleKey Maximum admissible key + */ + BucketPQ(const std::vector &keys, int64_t minAdmissibleKey, int64_t maxAdmissibleKey); + + /** + * Builds priority queue of the specified capacity @a capacity. + */ + BucketPQ(uint64_t capacity, int64_t minAdmissibleKey, int64_t maxAdmissibleKey); + + /** + * Default destructor + */ + ~BucketPQ() override = default; + + /** + * Inserts key-value pair (@key, @value). + */ + void insert(int64_t key, index value) override; + + /** + * Returns the element on top of the PrioQ. + */ + std::pair getMin(); + + /** + * Removes the element with minimum key and returns the key-value pair. + */ + std::pair extractMin() override; + + /** + * Modifies entry with value @a value. + * The entry is then set to @a newKey with the same value. + * If the corresponding key is not present, the element will be inserted. + */ + void changeKey(int64_t newKey, index value) override; + + /** + * @return Number of elements in PQ. + */ + uint64_t size() const override; + + /** + * @return Whether or not the PQ is empty. + */ + bool empty() const noexcept override; + + /** + * @return Whether or not the PQ contains the given element. + */ + bool contains(const index &value) const override; + + /** + * Removes key-value pair given by value @a val. + */ + void remove(const index &val) override; + + /** + * @return key to given value @val. + */ + virtual int64_t getKey(const index &val); +}; + +} /* namespace Aux */ +#endif // NETWORKIT_AUXILIARY_BUCKET_PQ_HPP_ diff --git a/vendor/include/networkit/auxiliary/Enforce.hpp b/vendor/include/networkit/auxiliary/Enforce.hpp new file mode 100644 index 0000000..5b92048 --- /dev/null +++ b/vendor/include/networkit/auxiliary/Enforce.hpp @@ -0,0 +1,117 @@ +#ifndef NETWORKIT_AUXILIARY_ENFORCE_HPP_ +#define NETWORKIT_AUXILIARY_ENFORCE_HPP_ + +#include +#include +#include + +namespace Aux { + +/** + * Enforces that @a b is true and throws an Exception otherwise. + * + * If provided, msg must not be null, otherwise the behavior of this + * function is undefined. + * + * @param b Boolean value whose truthiness should be enforced + * @param msg Message of the exception + */ +template +inline void enforce(bool b, const char *msg = "") { + assert(msg && "Message to enforce must not be nullptr"); + if (!b) { + throw Exception{msg}; + } +} + +/** + * Enforces that @a b is true and throws an Exception otherwise. + * + * If provided, msg must not be null, otherwise the behavior of this + * function is undefined. + * + * @param b Boolean value whose truthiness should be enforced + * @param msg Message of the exception + */ +template +inline void enforce(bool b, std::string_view msg) { + enforce(b, msg.data()); +} + +/** + * Checks that the provided fstream is opened and throws an exception otherwise. + * + * @param stream File stream whose openness should be enforced + */ +template +inline void enforceOpened(const Stream &stream) { + enforce(stream.is_open()); +} + +/** + * This namespace provides some Types with a static member-function `void enforce(bool)` + * that may check wether the argument is true and create some kind of failure otherwise. + */ +namespace Checkers { + +/** + * Checks the truthiness of the given boolean values through asserts. + */ +struct Asserter { + /** + * Enforces truthiness of the given boolean value @b through asserts. + * + * @param b Boolean value whose truthiness should be enforced + */ + static void enforce(bool b) { + assert(b); + (void)b; // prevent warnings in release-builds + } +}; + +/** + * Enforces truthiness of a given boolean value by throwing an exception in case of violation. + */ +struct Enforcer { + /** + * Enforces that @a b is true and throws an Exception otherwise. + * + * @param b Boolean value whose truthiness should be enforced + */ + static void enforce(bool b) { ::Aux::enforce(b); } +}; + +/** + * Calls std::terminate if the bool is false. + */ +struct Terminator { + /** + * Enforces truthiness of the given boolean value @b by terminating in case of violation. + * + * @param b Boolean value whose truthiness should be enforced + */ + static void enforce(bool b) { + if (!b) { + std::terminate(); + } + } +}; + +/** + * Won't look at the bool (not even in debug-mode, which is how this differs from Asserter). + */ +struct Ignorer { + /** + * Ignores the given boolean value and does not enforce anything. + * + * Useful for debugging purposes. + * + * @param Boolean whose value is ignored + */ + static void enforce(bool) {} +}; +} // namespace Checkers + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_ENFORCE_HPP_ diff --git a/vendor/include/networkit/auxiliary/FunctionTraits.hpp b/vendor/include/networkit/auxiliary/FunctionTraits.hpp new file mode 100644 index 0000000..cb98c69 --- /dev/null +++ b/vendor/include/networkit/auxiliary/FunctionTraits.hpp @@ -0,0 +1,74 @@ +#ifndef NETWORKIT_AUXILIARY_FUNCTION_TRAITS_HPP_ +#define NETWORKIT_AUXILIARY_FUNCTION_TRAITS_HPP_ + +#include +#include + +namespace Aux { + +// Code taken from https://functionalcpp.wordpress.com/2013/08/05/function-traits/ and slightly +// modified + +template +struct FunctionTraits; + +// function pointer +template +struct FunctionTraits : public FunctionTraits {}; + +template +struct FunctionTraits { + using result_type = R; + + static constexpr size_t arity = sizeof...(Args); + + template + struct arg_impl; + template + struct arg_impl {}; + template + struct arg_impl { + using type = typename std::tuple_element>::type; + }; + + template + using arg = arg_impl < N, + N; +}; + +// member function pointer +template +struct FunctionTraits : public FunctionTraits {}; + +// const member function pointer +template +struct FunctionTraits : public FunctionTraits {}; + +// member object pointer +template +struct FunctionTraits : public FunctionTraits {}; + +// functor +template +struct FunctionTraits { +private: + using call_type = FunctionTraits; + +public: + using result_type = typename call_type::result_type; + + static constexpr size_t arity = call_type::arity - 1; + + template + using arg = typename call_type::template arg; +}; + +template +struct FunctionTraits : public FunctionTraits {}; + +template +struct FunctionTraits : public FunctionTraits {}; + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_FUNCTION_TRAITS_HPP_ diff --git a/vendor/include/networkit/auxiliary/HashUtils.hpp b/vendor/include/networkit/auxiliary/HashUtils.hpp new file mode 100644 index 0000000..c21fb79 --- /dev/null +++ b/vendor/include/networkit/auxiliary/HashUtils.hpp @@ -0,0 +1,28 @@ +#ifndef NETWORKIT_AUXILIARY_HASH_UTILS_HPP_ +#define NETWORKIT_AUXILIARY_HASH_UTILS_HPP_ + +#include + +namespace Aux { + +template +void hashCombine(std::size_t &seed, T const &v) { + // The Boost Software License, Version 1.0 applies to this function. + // See https://www.boost.org/LICENSE_1_0.txt + // https://www.boost.org/doc/libs/1_75_0/doc/html/hash/reference.html#boost.hash_combine + seed ^= std::hash()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +struct PairHash { + template + std::size_t operator()(const std::pair &pair) const { + std::size_t seed = 0; + hashCombine(seed, pair.first); + hashCombine(seed, pair.second); + return seed; + } +}; + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_HASH_UTILS_HPP_ diff --git a/vendor/include/networkit/auxiliary/IncrementalUniformRandomSelector.hpp b/vendor/include/networkit/auxiliary/IncrementalUniformRandomSelector.hpp new file mode 100644 index 0000000..cff2ccc --- /dev/null +++ b/vendor/include/networkit/auxiliary/IncrementalUniformRandomSelector.hpp @@ -0,0 +1,52 @@ +#ifndef NETWORKIT_AUXILIARY_INCREMENTAL_UNIFORM_RANDOM_SELECTOR_HPP_ +#define NETWORKIT_AUXILIARY_INCREMENTAL_UNIFORM_RANDOM_SELECTOR_HPP_ + +#include + +#include + +namespace Aux { + +/** + * Select uniformly at random from a set of elements + * that is discovered incrementally. Every time you + * discover a new element, you tell the selector and + * it will tell if you should keep the new element or + * your old element. As more and more elements are + * discovered, it will be less and less likely that + * the new element is chosen in order to ensure that + * the selection is uniformly at random. The process + * can be reset when a new class of elements is found + * that shall be used instead. + */ +class IncrementalUniformRandomSelector { +public: + /** + * Initialize the random select for one element. + */ + IncrementalUniformRandomSelector() : counter(1){}; + + /** + * Add the next element. + * + * Note that this must not be called for the first element. + * + * @return If the new element shall be accepted/kept. + */ + bool addElement() { + ++counter; + return (Random::real() < 1.0 / static_cast(counter)); + } + + /** + * Reset the process to one element again. + */ + void reset() { counter = 1; } + +private: + size_t counter; +}; + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_INCREMENTAL_UNIFORM_RANDOM_SELECTOR_HPP_ diff --git a/vendor/include/networkit/auxiliary/Log.hpp b/vendor/include/networkit/auxiliary/Log.hpp new file mode 100644 index 0000000..9ab0648 --- /dev/null +++ b/vendor/include/networkit/auxiliary/Log.hpp @@ -0,0 +1,119 @@ +#ifndef NETWORKIT_AUXILIARY_LOG_HPP_ +#define NETWORKIT_AUXILIARY_LOG_HPP_ + +#include +#include +#include + +#include + +#ifdef _MSC_VER +#define NETWORKT_PRETTY_FUNCTION __FUNCSIG__ +#else +#define NETWORKT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#endif // _MSC_VER + +/// Logging without format string +#define LOG_AT(level, ...) \ + ::Aux::Log::log({__FILE__, NETWORKT_PRETTY_FUNCTION, __LINE__}, level, __VA_ARGS__) +#define FATAL(...) LOG_AT(::Aux::Log::LogLevel::FATAL, __VA_ARGS__) +#define ERROR(...) LOG_AT(::Aux::Log::LogLevel::ERROR, __VA_ARGS__) +#define WARN(...) LOG_AT(::Aux::Log::LogLevel::WARN, __VA_ARGS__) +#define INFO(...) LOG_AT(::Aux::Log::LogLevel::INFO, __VA_ARGS__) + +/// Logging with format string +#define LOG_ATF(level, ...) \ + ::Aux::Log::logF({__FILE__, NETWORKT_PRETTY_FUNCTION, __LINE__}, level, __VA_ARGS__) +#define FATALF(...) LOG_ATF(::Aux::Log::LogLevel::FATAL, __VA_ARGS__) +#define ERRORF(...) LOG_ATF(::Aux::Log::LogLevel::ERROR, __VA_ARGS__) +#define WARNF(...) LOG_ATF(::Aux::Log::LogLevel::WARN, __VA_ARGS__) +#define INFOF(...) LOG_ATF(::Aux::Log::LogLevel::INFO, __VA_ARGS__) + +// DEBUG and TRACE are no-ops if NETWORKIT_RELEASE_LOGGING is defined. +#if defined(NETWORKIT_RELEASE_LOGGING) +#define NETWORKIT_LOG_DUMMY(...) \ + do { \ + } while (false) +#define DEBUG(...) NETWORKIT_LOG_DUMMY(__VA_ARGS__) +#define DEBUGF(...) NETWORKIT_LOG_DUMMY(__VA_ARGS__) +#define TRACE(...) NETWORKIT_LOG_DUMMY(__VA_ARGS__) +#define TRACEF(...) NETWORKIT_LOG_DUMMY(__VA_ARGS__) +#define TRACEPOINT NETWORKIT_LOG_DUMMY() +#else +#define DEBUG(...) LOG_AT(::Aux::Log::LogLevel::DEBUG, __VA_ARGS__) +#define TRACE(...) LOG_AT(::Aux::Log::LogLevel::TRACE, __VA_ARGS__) + +#define DEBUGF(...) LOG_ATF(::Aux::Log::LogLevel::DEBUG, __VA_ARGS__) +#define TRACEF(...) LOG_ATF(::Aux::Log::LogLevel::TRACE, __VA_ARGS__) + +#define TRACEPOINT LOG_AT(::Aux::Log::LogLevel::TRACE, "tracepoint") +#endif // defined(NETWORKIT_RELEASE_LOGGING) + +namespace Aux { +namespace Log { + +struct Location { + const char *file; + const char *function; + const int line; +}; + +enum class LogLevel { + TRACE, + DEBUG, + INFO, + WARN, + ERROR, + FATAL, + QUIET, // Emits no log messages at all. + trace = TRACE, // this + following added for backwards compatibility + debug = DEBUG, + info = INFO, + warn = WARN, + error = ERROR, + fatal = FATAL, + quiet = QUIET +}; + +/** + * Accept loglevel as string and set. + * @param logLevel as string + */ +void setLogLevel(std::string_view logLevel); + +/** + * @return current loglevel as string + */ +std::string getLogLevel(); + +namespace Impl { +void log(const Location &loc, LogLevel p, std::string_view msg); +} // namespace Impl + +///! Returns true iff logging at the provided level is currently activated +bool isLogLevelEnabled(LogLevel p) noexcept; + +template +void log(const Location &loc, LogLevel p, const T &...args) { + if (!isLogLevelEnabled(p)) + return; + + std::stringstream stream; + printToStream(stream, args...); + Impl::log(loc, p, stream.str()); +} + +template +void logF(const Location &loc, LogLevel p, std::string_view format, const T &...args) { + if (!isLogLevelEnabled(p)) + return; + + std::stringstream stream; + printToStreamF(stream, format, args...); + Impl::log(loc, p, stream.str()); +} + +} // namespace Log +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_LOG_HPP_ diff --git a/vendor/include/networkit/auxiliary/MissingMath.hpp b/vendor/include/networkit/auxiliary/MissingMath.hpp new file mode 100644 index 0000000..23c4ef2 --- /dev/null +++ b/vendor/include/networkit/auxiliary/MissingMath.hpp @@ -0,0 +1,48 @@ +/* + * MissingMath.hpp + * + * Created on: 21.03.2013 + * Author: cls + */ + +#ifndef NETWORKIT_AUXILIARY_MISSING_MATH_HPP_ +#define NETWORKIT_AUXILIARY_MISSING_MATH_HPP_ + +#include +#include +#include +#include + +namespace Aux { + +/** + * Math functions not provided by the standard library. + */ +namespace MissingMath { + +inline int64_t binomial(int64_t n, int64_t k) { + if (k == 0) + return 1; + if (2 * k > n) + return binomial(n, n - k); + + int64_t b = n - k + 1; + for (int64_t i = 2; i <= k; ++i) { + b = b * (n - k + i); + b = b / i; + } + return b; +} + +inline double log_b(double x, double b) { + if (x == 0) { + throw std::domain_error("log(0) is undefined"); + } + assert(std::log(b) != 0); + return std::log(x) / std::log(b); +} + +} /* namespace MissingMath */ + +} /* namespace Aux */ +#endif // NETWORKIT_AUXILIARY_MISSING_MATH_HPP_ diff --git a/vendor/include/networkit/auxiliary/Multiprecision.hpp b/vendor/include/networkit/auxiliary/Multiprecision.hpp new file mode 100644 index 0000000..65159fe --- /dev/null +++ b/vendor/include/networkit/auxiliary/Multiprecision.hpp @@ -0,0 +1,17 @@ +/* + * Multiprecision.hpp + * + * Created on: 21.03.2013 + * Author: cls + */ + +#ifndef NETWORKIT_AUXILIARY_MULTIPRECISION_HPP_ +#define NETWORKIT_AUXILIARY_MULTIPRECISION_HPP_ + +#include + +namespace NetworKit { +using bigfloat = ttmath::Big; ///< big floating point number +} + +#endif // NETWORKIT_AUXILIARY_MULTIPRECISION_HPP_ diff --git a/vendor/include/networkit/auxiliary/NumberParsing.hpp b/vendor/include/networkit/auxiliary/NumberParsing.hpp new file mode 100644 index 0000000..2fcc378 --- /dev/null +++ b/vendor/include/networkit/auxiliary/NumberParsing.hpp @@ -0,0 +1,307 @@ +#ifndef NETWORKIT_AUXILIARY_NUMBER_PARSING_HPP_ +#define NETWORKIT_AUXILIARY_NUMBER_PARSING_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Aux { +namespace Parsing { + +namespace Impl { + +template +std::tuple dropSpaces(CharIterator it, CharIterator end); + +template +double powerOf10(Integer exp); + +class IntegerTag {}; + +template +std::tuple strTo(CharIterator it, CharIterator end, IntegerTag); + +class RealTag {}; + +template +std::tuple strTo(CharIterator it, CharIterator end, RealTag); + +template +using ArithmeticTag = typename std::conditional< + std::is_integral::value, IntegerTag, + typename std::conditional::value, RealTag, void>::type>::type; + +} // namespace Impl + +/** + * Parses a range of characters as number. + * + * @param Number must be either a floating-point-type or an integer-type + * @param CharIterator must be a valid input-iterator over a type that is + * implicitly convertable to char + * @param ValidationPolicy must be a type that is compatible to the checkers from Enforce.h, + * the default is Asserter, which will check conditions via assert() + * @param it the start of the character-range + * @param end the end of the character-range + * + * Requirements: The range [it, end) must contain a valid number. + * + * @return: A tuple of the parsed value and the iterator after parsing the number and dropping + * any surrounding whitespace. + * + */ +template +std::tuple strTo(CharIterator it, CharIterator end) { + return Impl::strTo(it, end, + Impl::ArithmeticTag{}); +} + +namespace Impl { + +template +std::tuple strTo(CharIterator it, const CharIterator end, IntegerTag) { + using Impl::dropSpaces; + ValidationPolicy::enforce(it != end); + + char c = *it; + std::tie(it, c) = dropSpaces(it, end); + + bool isNegative = false; + if (std::is_signed::value) { // this should be optimized away entirely + switch (c) { + case '-': + isNegative = true; + // fallthrough + case '+': + ++it; + if (it == end) { + throw std::invalid_argument{"string contains no digits after sign"}; + } + c = *it; + break; + default: + break; + } + } + + if (!isdigit(c)) { + throw std::invalid_argument{"string contains no digits"}; + } + + Integer val = 0; + while (true) { + ValidationPolicy::enforce(std::numeric_limits::max() / 10 >= val); + + val *= 10; + + c -= '0'; + ValidationPolicy::enforce(std::numeric_limits::max() - c >= val); + + val += c; + + ++it; + if (it == end) { + break; + } + c = *it; + if (!isdigit(c)) { + break; + } + } + + if (isNegative) { + val = -val; + } + + std::tie(it, c) = dropSpaces(it, end); + + return std::make_tuple(val, it); +} + +template +std::tuple strTo(CharIterator it, const CharIterator end, RealTag) { + + static_assert(std::numeric_limits::max_digits10 + <= std::numeric_limits::digits10, + "can't safe mantissa in biggest integer"); + + using Impl::dropSpaces; + using Impl::powerOf10; + + char c; + bool isNegative = false; + std::uintmax_t mantissa = 0; + int exp = 0; + + auto makeReturnValue = [&]() { + Real fp_mantissa = mantissa; + Real value = fp_mantissa * powerOf10(exp); + if (isNegative) { + value = -value; + } + return std::make_tuple(value, it); + }; + + // drop whitespace: + std::tie(it, c) = dropSpaces(it, end); + + ValidationPolicy::enforce(it != end); + + // set sign: + switch (c) { + case '-': + isNegative = true; + // fallthrough + case '+': + ++it; + if (it == end) { + throw std::invalid_argument{"string contains no digits"}; + } + c = *it; + break; + default: + break; + } + + // number of decimal digits that can be stored in the mantissa and the used integer + unsigned remainingDigits = std::numeric_limits::max_digits10; + + // read 'big' part of the mantissa: + while (remainingDigits > 0) { + if (!isdigit(c)) { + break; + } + --remainingDigits; + mantissa *= 10; + mantissa += c - '0'; + ++it; + if (it == end) { + return makeReturnValue(); + } + c = *it; + } + if (remainingDigits == 0) { + if (isdigit(c)) { + // round correctly: + if (c - '0' >= 5) { + ++mantissa; + } + } + while (isdigit(c)) { + ++exp; + ++it; + if (it == end) { + break; + } + c = *it; + } + } + // read 'small' part of the mantissa + if (c == '.') { + ++it; + if (it == end) { + return makeReturnValue(); + } + c = *it; + while (remainingDigits > 0) { + if (!isdigit(c)) { + break; + } + --exp; + --remainingDigits; + mantissa *= 10; + mantissa += c - '0'; + ++it; + if (it == end) { + return makeReturnValue(); + } + c = *it; + } + if (isdigit(c)) { + // round correctly: + if (c - '0' >= 5) { + ++mantissa; + } + } + // skip the remaining digits: + it = std::find_if_not(it, end, isdigit); + if (it == end) { + return makeReturnValue(); + } + c = *it; + } + + // calculate the final exponent: + if (c == 'e' || c == 'E') { + ++it; + int tmp; + // we need to pass IntegerTag explicitly here because we are in a + // nested namespace. This shouldn't be required anywhere else + std::tie(tmp, it) = strTo(it, end, IntegerTag{}); + exp += tmp; + } + + // drop further whitespace: + std::tie(it, c) = dropSpaces(it, end); + + return makeReturnValue(); +} + +template +std::tuple dropSpaces(CharIterator it, CharIterator end) { + char c = 0; + while (it != end && std::isspace((c = *it))) { + ++it; + } + return std::make_tuple(it, c); +} + +template +double powerOf10(Integer exp) { + if (exp < 0) { + return 1.0 / powerOf10(-exp); + } + switch (exp) { + case 0: + return 1; + case 1: + return 10; + case 2: + return 100; + case 3: + return 1000; + case 4: + return 10000; + case 5: + return 100000; + case 6: + return 1000000; + case 7: + return 10000000; + case 8: + return 100000000; + case 9: + return 1000000000; + default: + auto tmp = powerOf10(exp / 2); + if (exp % 2 == 0) { + return tmp * tmp; + } else { + return tmp * tmp * 10; + } + } +} + +} // namespace Impl + +} // namespace Parsing +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_NUMBER_PARSING_HPP_ diff --git a/vendor/include/networkit/auxiliary/NumericTools.hpp b/vendor/include/networkit/auxiliary/NumericTools.hpp new file mode 100644 index 0000000..5fd35f6 --- /dev/null +++ b/vendor/include/networkit/auxiliary/NumericTools.hpp @@ -0,0 +1,57 @@ +/* + * NumericTools.hpp + * + * Created on: 15.02.2013 + * Author: Christian Staudt (christian.staudt@kit.edu) + */ + +#ifndef NETWORKIT_AUXILIARY_NUMERIC_TOOLS_HPP_ +#define NETWORKIT_AUXILIARY_NUMERIC_TOOLS_HPP_ + +#include + +namespace Aux { + +/** + * Tools to deal with limited precision in numeric computations. + */ +namespace NumericTools { + +static constexpr double machineEpsilon = std::numeric_limits::epsilon(); + +static constexpr double acceptableError = 1e-12; + +template +bool willOverflow(const T &pX, const T &pValue, const T &pMax = std::numeric_limits::max()) { + return pMax - pValue < pX; +} + +template +bool willUnderflow(const T &pX, const T &pValue, const T &pMin = std::numeric_limits::min()) { + return pMin + pValue > pX; +} + +/** + * Test doubles for equality within a given error. + */ +bool equal(double x, double y, double error = acceptableError); + +/** + * Test doubles for equality within a given error. + */ +bool le(double x, double y, double error = acceptableError); + +/** + * Test doubles for equality within a given error. + */ +bool ge(double x, double y, double error = acceptableError); + +/** + * Test doubles for equality within the smallest possible error. + */ +bool logically_equal(double a, double b, double error_factor = 1.0); + +} /* namespace NumericTools */ + +} // namespace Aux +#endif // NETWORKIT_AUXILIARY_NUMERIC_TOOLS_HPP_ diff --git a/vendor/include/networkit/auxiliary/Parallel.hpp b/vendor/include/networkit/auxiliary/Parallel.hpp new file mode 100644 index 0000000..c147ee1 --- /dev/null +++ b/vendor/include/networkit/auxiliary/Parallel.hpp @@ -0,0 +1,56 @@ +/* + * Header which provides parallel STL implementations when available. + */ +#ifndef NETWORKIT_AUXILIARY_PARALLEL_HPP_ +#define NETWORKIT_AUXILIARY_PARALLEL_HPP_ + +#include +#include + +#if ((defined(__GNUC__) || defined(__GNUG__)) \ + && !(defined(__clang__) || defined(__INTEL_COMPILER))) \ + && defined _OPENMP +#include +#else +#define NETWORKIT_NO_PARALLEL_STL +#include +#endif + +namespace Aux { +namespace Parallel { +#ifdef NETWORKIT_NO_PARALLEL_STL +using std::max_element; +using std::sort; +#else +using __gnu_parallel::max_element; +using __gnu_parallel::sort; +#endif // NETWORKIT_NO_PARALLEL_STL + +template +void atomic_set(std::atomic &target, const ValueType &input, Comp shallSet) { + // load current value + auto curValue = target.load(std::memory_order_relaxed); + + do { + if (!shallSet(input, curValue)) + break; // skip if shall not be set (anymore) + // set new value unless current value has been changed in the meantime, if current value has + // changed load it (so we can compare again) + } while (!target.compare_exchange_weak(curValue, input, std::memory_order_release, + std::memory_order_relaxed)); +} + +template +void atomic_max(std::atomic &target, const ValueType &input) { + atomic_set(target, input, std::greater()); +} + +template +void atomic_min(std::atomic &target, const ValueType &input) { + atomic_set(target, input, std::less()); +} + +} // namespace Parallel +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_PARALLEL_HPP_ diff --git a/vendor/include/networkit/auxiliary/Parallelism.hpp b/vendor/include/networkit/auxiliary/Parallelism.hpp new file mode 100644 index 0000000..3398ccb --- /dev/null +++ b/vendor/include/networkit/auxiliary/Parallelism.hpp @@ -0,0 +1,33 @@ +/* + * Parallelism.hpp + * + * Control functions related to parallelism. + * + * Created on: 13.11.2013 + * Author: Christian Staudt (christian.staudt@kit.edu) + */ + +#ifndef NETWORKIT_AUXILIARY_PARALLELISM_HPP_ +#define NETWORKIT_AUXILIARY_PARALLELISM_HPP_ + +namespace Aux { + +/** + * Set the number of threads available to the program. + */ +void setNumberOfThreads(int nThreads); + +/** + * + * @return The number of threads currently running. + */ +int getCurrentNumberOfThreads(); + +/** + * + * @return The maximum number of threads available to the program. + */ +int getMaxNumberOfThreads(); +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_PARALLELISM_HPP_ diff --git a/vendor/include/networkit/auxiliary/PrioQueue.hpp b/vendor/include/networkit/auxiliary/PrioQueue.hpp new file mode 100644 index 0000000..e685cd7 --- /dev/null +++ b/vendor/include/networkit/auxiliary/PrioQueue.hpp @@ -0,0 +1,252 @@ +/* + * PrioQueue.hpp + * + * Created on: 02.03.2017 + * Author: Henning + */ + +#ifndef NETWORKIT_AUXILIARY_PRIO_QUEUE_HPP_ +#define NETWORKIT_AUXILIARY_PRIO_QUEUE_HPP_ + +#include +#include +#include +#include + +#include + +namespace Aux { + +/** + * Priority queue with extract-min and decrease-key. + * The type Val takes on integer values between 0 and n-1. + * O(n log n) for construction, O(log n) for typical operations. + */ +template +class PrioQueue { +private: + using ElemType = std::pair; + + std::set pqset; // TODO: would std::map work and simplify things? + std::vector mapValToKey; + + const Key undefined = std::numeric_limits::max(); // TODO: make static + +protected: + /** + * Default constructor without functionality. Only here for derived classes! + */ + PrioQueue() = default; + + /** + * Removes key-value pair given by @a elem. + */ + virtual void remove(const ElemType &elem); + + /** + * @return current content of queue + */ + virtual std::set> content() const; + +public: + /** + * Builds priority queue from the vector @a keys, values are indices + * of @a keys. + */ + PrioQueue(const std::vector &keys); + + /** + * Builds priority queue of the specified capacity @a capacity. + */ + PrioQueue(uint64_t capacity); + + /** + * Default destructor + */ + virtual ~PrioQueue() = default; + + /** + * Inserts key-value pair stored in @a elem. + */ + virtual void insert(Key key, Value value); + + /** + * Returns the @a n-th element in the priority queue. + */ + virtual ElemType peekMin(size_t n = 0); + + /** + * Removes the element with minimum key and returns it. + */ + virtual ElemType extractMin(); + + /** + * Modifies entry with value @a value. + * The entry is then set to @a newKey with the same value. + * If the corresponding key is not present, the element will be inserted. + */ + virtual void changeKey(Key newKey, Value value); + + /** + * @return Number of elements in PQ. + */ + virtual uint64_t size() const; + + /** + * @return Whether or not the PQ is empty. + */ + virtual bool empty() const noexcept; + + /** + * @return Whether or not the PQ contains the given value. + */ + virtual bool contains(const Value &value) const; + + /** + * Removes key-value pair given by value @a val. + */ + virtual void remove(const Value &val); + + /** + * Removes all the elements from the priority queue. + */ + virtual void clear(); + + /** + * Iterates over all the elements of the priority queue and call @a handle + * (lambda closure). + */ + template + void forElements(L handle) const; + + /** + * Iterates over all the elements of the priority queue while the condition + * is satisfied and call @a handle (lambda closure). + */ + template + void forElementsWhile(C condition, L handle) const; + + /** + * DEBUGGING + */ + virtual void print() { + DEBUG("num entries: ", mapValToKey.size()); + for (uint64_t i = 0; i < mapValToKey.size(); ++i) { + DEBUG("key: ", mapValToKey[i], ", val: ", i, "\n"); + } + } +}; + +template +Aux::PrioQueue::PrioQueue(const std::vector &keys) { + mapValToKey.resize(keys.size()); + uint64_t index = 0; + for (auto key : keys) { + insert(key, index); + ++index; + } +} + +template +Aux::PrioQueue::PrioQueue(uint64_t capacity) { + mapValToKey.resize(capacity); +} + +template +void Aux::PrioQueue::insert(Key key, Value value) { + if (value >= mapValToKey.size()) { + uint64_t doubledSize = 2 * mapValToKey.size(); + assert(value < doubledSize); + mapValToKey.resize(doubledSize); + } + pqset.insert(std::make_pair(key, value)); + mapValToKey.at(value) = key; +} + +template +void Aux::PrioQueue::remove(const ElemType &elem) { + remove(elem.second); +} + +template +void Aux::PrioQueue::remove(const Value &val) { + Key key = mapValToKey.at(val); + pqset.erase(std::make_pair(key, val)); + mapValToKey.at(val) = undefined; +} + +template +std::pair Aux::PrioQueue::peekMin(size_t n) { + assert(pqset.size() > n); + ElemType elem = *std::next(pqset.begin(), n); + return elem; +} + +template +std::pair Aux::PrioQueue::extractMin() { + assert(!pqset.empty()); + ElemType elem = (*pqset.begin()); + remove(elem); + return elem; +} + +template +void Aux::PrioQueue::changeKey(Key newKey, Value value) { + // find and remove element with given key + remove(value); + + // insert element with new value + insert(newKey, value); +} + +template +uint64_t Aux::PrioQueue::size() const { + return pqset.size(); +} + +template +bool Aux::PrioQueue::empty() const noexcept { + return pqset.empty(); +} + +template +bool Aux::PrioQueue::contains(const Value &value) const { + return value < mapValToKey.size() && mapValToKey.at(value) != undefined; +} + +template +std::set> Aux::PrioQueue::content() const { + return pqset; +} + +template +void Aux::PrioQueue::clear() { + pqset.clear(); + auto capacity = mapValToKey.size(); + mapValToKey.clear(); + mapValToKey.resize(capacity); +} + +template +template +void Aux::PrioQueue::forElements(L handle) const { + for (auto it = pqset.begin(); it != pqset.end(); ++it) { + ElemType elem = *it; + handle(elem.first, elem.second); + } +} + +template +template +void Aux::PrioQueue::forElementsWhile(C condition, L handle) const { + for (auto it = pqset.begin(); it != pqset.end(); ++it) { + if (!condition()) { + break; + } + ElemType elem = *it; + handle(elem.first, elem.second); + } +} + +} /* namespace Aux */ +#endif // NETWORKIT_AUXILIARY_PRIO_QUEUE_HPP_ diff --git a/vendor/include/networkit/auxiliary/Random.hpp b/vendor/include/networkit/auxiliary/Random.hpp new file mode 100644 index 0000000..8dbe9db --- /dev/null +++ b/vendor/include/networkit/auxiliary/Random.hpp @@ -0,0 +1,122 @@ +/* + * Random.hpp + * + * Created on: 02.01.2014 + * Author: FJW + */ + +#ifndef NETWORKIT_AUXILIARY_RANDOM_HPP_ +#define NETWORKIT_AUXILIARY_RANDOM_HPP_ + +#include +#include +#include +#include +#include + +namespace Aux { + +/** + * Provides several functions for random-numbers. + * + * All functions are guaranteed to be thread-safe. + */ +namespace Random { + +/** + * Sets the random seed that is used globally. + * @param seed The seed value + * @param useThreadId If the thread id shall be added to the seed value + */ +void setSeed(uint64_t seed, bool useThreadId); + +/** + * @returns a high-quality random seed for an URNG. + */ +uint64_t getSeed(); + +/** + * @returns a reference to a seeded URNG that is thread_local. + */ +std::mt19937_64 &getURNG(); + +/** + * @returns an integer distributed uniformly in an inclusive range; + * @param upperBound the upper bound, default = UNINT64_T_MAX + * @param lowerBound the lower bound, default = 0 + * + * @warning Compared to obtaining a reference to a generator using + * @ref getURNG() and then using a local std::uniform_int_distribution, + * this method incurs a slow-down of up to 30%. Consider avoiding it + * in hot sections. + */ +uint64_t integer(); +uint64_t integer(uint64_t upperBound); +uint64_t integer(uint64_t lowerBound, uint64_t upperBound); + +/** + * @returns a double distributed uniformly in a half-open range: [lowerBound, upperBound) + * @param upperBound default = 1.0 + * @param lowerBound default = 0.0 + * + * @warning Compared to obtaining a reference to a generator using + * @ref getURNG() and then using a local std::uniform_real_distribution, + * this method incurs a slow-down of up to 30%. Consider avoiding it + * in hot sections. + */ +double real(); +double real(double upperBound); +double real(double lowerBound, double upperBound); + +/** + * @returns a double distributed uniformly in the range [0, 1] + * @note this differs from real() in returning a value in a closed instead of a half-open range. + * + * @warning Compared to obtaining a reference to a generator using + * @ref getURNG() and then using a local std::uniform_int_distribution, + * this method incurs a slow-down of up to 30%. Consider avoiding it + * in hot sections. + */ +double probability(); + +/** + * @returns a size_t in the range [0, max - 1] that can for example be used to + * access a random element of a container. + */ +std::size_t index(std::size_t max); + +/** + * @returns a uniform random choice from an indexable container of elements. + */ +template +typename Container::const_reference choice(const Container &container) { + return container[index(container.size())]; +} + +/** + * @returns a weighted random choice from a vector of elements with given weights. + */ +template +const Element &weightedChoice(const std::vector> &weightedElements) { + if (weightedElements.empty()) + throw std::runtime_error("Random::weightedChoice: input size equal to 0"); + double total = 0.0; + for (const auto &entry : weightedElements) { + assert(entry.second >= 0.0 && "This algorithm only works with non-negative weights"); + total += entry.second; + } + double r = Aux::Random::real(total); + for (const auto &entry : weightedElements) { + if (r < entry.second) { + return entry.first; + } + r -= entry.second; + } + throw std::runtime_error( + "Random::weightedChoice: should never get here"); // should never get here +} + +} // namespace Random +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_RANDOM_HPP_ diff --git a/vendor/include/networkit/auxiliary/SetIntersector.hpp b/vendor/include/networkit/auxiliary/SetIntersector.hpp new file mode 100644 index 0000000..500b667 --- /dev/null +++ b/vendor/include/networkit/auxiliary/SetIntersector.hpp @@ -0,0 +1,72 @@ +/* + * SetIntersector.hpp + * + * Created on: 14.05.2014 + * Author: Henning + */ + +#ifndef NETWORKIT_AUXILIARY_SET_INTERSECTOR_HPP_ +#define NETWORKIT_AUXILIARY_SET_INTERSECTOR_HPP_ + +#include +#include +#include + +namespace Aux { + +/** + * Provides set intersection for sets with entries from 0 to an upper bound (exclusive). + * Preprocessing time: Linear time for object creation (creates a bit vector of size upperBound. + * Query time: O(|A|+|B|) for two sets A and B. + * Space complexity: upperBound + 64 bits. + */ +template +class SetIntersector { +public: + /** + * @param upperBound Exclusive upper bound for IDs of set members. + */ + SetIntersector(T upperBound); + + /** + * @return Intersection of sets provided in @a A and @a B. + */ + std::set intersect(const std::vector &A, const std::vector &B); + +private: + std::vector bv; + uint64_t n; +}; + +} // namespace Aux + +template +inline Aux::SetIntersector::SetIntersector(T upperBound) : n(upperBound) { + bv.resize(n, false); +} + +template +inline std::set Aux::SetIntersector::intersect(const std::vector &A, + const std::vector &B) { + const std::vector &smaller = (A.size() <= B.size()) ? A : B; + const std::vector &larger = (A.size() <= B.size()) ? B : A; + + for (auto entry : smaller) { + bv[entry] = true; + } + + std::set result; + for (auto entry : larger) { + if (bv[entry]) { + result.insert(entry); + } + } + + for (auto entry : smaller) { + bv[entry] = false; + } + + return result; +} + +#endif // NETWORKIT_AUXILIARY_SET_INTERSECTOR_HPP_ diff --git a/vendor/include/networkit/auxiliary/SignalHandling.hpp b/vendor/include/networkit/auxiliary/SignalHandling.hpp new file mode 100644 index 0000000..8c9a6ef --- /dev/null +++ b/vendor/include/networkit/auxiliary/SignalHandling.hpp @@ -0,0 +1,39 @@ +#ifndef NETWORKIT_AUXILIARY_SIGNAL_HANDLING_HPP_ +#define NETWORKIT_AUXILIARY_SIGNAL_HANDLING_HPP_ + +#include +#include + +namespace Aux { + +/** + * Signal handler class used to support CTRL+c user interrupts. + * This class works by registering a interrupt handler during its lifetime; to check if an interrupt + * has been received or to immediately stop running a (long-running) algorithm, use the + * `assureRunning` or `isRunning` member functions. + * @note Make sure to delete this object when it is no longer required to free up the interrupt + * handler again for other code such as the python runtime! + */ +class SignalHandler { +public: + SignalHandler(); + + ~SignalHandler(); + + void assureRunning(); + + bool isRunning(); + + /** + * Special Exception to indicate that a SIGINT has been received. + */ + class InterruptException : public std::exception { + public: + InterruptException() : std::exception() {} + const char *what() const noexcept override { return "Received CTRL+C/SIGINT"; } + }; +}; + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_SIGNAL_HANDLING_HPP_ diff --git a/vendor/include/networkit/auxiliary/SortedList.hpp b/vendor/include/networkit/auxiliary/SortedList.hpp new file mode 100644 index 0000000..7d5792d --- /dev/null +++ b/vendor/include/networkit/auxiliary/SortedList.hpp @@ -0,0 +1,128 @@ +/* + * SortedList.hpp + * + * Created on: 21.09.2018 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_AUXILIARY_SORTED_LIST_HPP_ +#define NETWORKIT_AUXILIARY_SORTED_LIST_HPP_ + +#include +#include + +namespace Aux { +/* + * Keeps a sorted list of pairs with at most k elements. + * If more than k elements are inserted, the elements with smallest value are + * removed. The list is implemented on top of vector, thus the insert operation + * takes O(k) time. + * + * Warning: this sorted list was designed for the Kadabra algorithm; we assume + * that all the newly inserted elements have a value that is greater or equal + * to 0 if not already present in the list, or greater or equal their previous + * value. + * TODO: generalize this data structure. + */ +class SortedList { +private: + std::vector> elements; + std::vector position; + uint64_t virtualSize; + const uint64_t size; + const uint64_t maxKey; + +public: + /** + * Creates a SortedList of size @a size accepting key values from 0 to + * @a maxKey. + */ + SortedList(uint64_t size, uint64_t maxKey); + + /** + * Insert a key-value element. + */ + void insert(uint64_t newElement, double newValue); + + /** + * Returns the value at position @a i in the ranking. + */ + double getValue(const uint64_t i) const { return elements[i].second; } + + /** + * Returns the element at position @a i in the ranking. + */ + uint64_t getElement(const uint64_t i) const { return elements[i].first; } + + /** + * Returns the number of elements stored in the list. + */ + uint64_t getSize() const { return virtualSize; } + + /** + * Removes all the elements in the list. + */ + void clear(); +}; + +inline SortedList::SortedList(const uint64_t size, const uint64_t maxKey) + : size(size), maxKey(maxKey) { + if (maxKey < size) { + throw std::runtime_error("maxKey must be bigger than the size."); + } + clear(); +} + +inline void SortedList::clear() { + elements.resize(size); + position.resize(maxKey); + uint64_t i; + for (i = 0; i < size; ++i) { + elements[i] = std::make_pair(i, 0.); + position[i] = i; + } + for (i = size; i < maxKey; ++i) { + position[i] = i; + } + virtualSize = 0; +} + +inline void SortedList::insert(const uint64_t newElement, const double newValue) { + uint64_t ub = std::upper_bound(elements.begin(), elements.begin() + virtualSize, newValue, + [&](const double val, const std::pair pair) { + return val > pair.second; + }) + - elements.begin(); + + uint64_t oldPos; + // We assume that if the same key is inserted again, its value will be + // greater than before (i.e., oldPos >= ub). + if (ub < size) { + oldPos = std::min(position[newElement], size - 1); + if (position[newElement] < size) { + assert(elements[ub].second <= newValue); + } + if (virtualSize < size && oldPos >= virtualSize) { + ++virtualSize; + } + + if (ub < oldPos) { + std::rotate(elements.begin() + ub, elements.begin() + oldPos, + elements.begin() + oldPos + 1); + + if (oldPos == size - 1) { + ++position[elements[ub].first]; + } + + elements[ub] = std::make_pair(newElement, newValue); + for (auto it = elements.begin() + ub + 1; it < elements.begin() + oldPos + 1; ++it) { + ++position[(*it).first]; + } + } else { + elements[ub].second = newValue; + } + } +} +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_SORTED_LIST_HPP_ diff --git a/vendor/include/networkit/auxiliary/SparseVector.hpp b/vendor/include/networkit/auxiliary/SparseVector.hpp new file mode 100644 index 0000000..407518f --- /dev/null +++ b/vendor/include/networkit/auxiliary/SparseVector.hpp @@ -0,0 +1,215 @@ +/* + * SparseVector.hpp + * + * Created: 2019-10-15 + * Author: Armin Wiebigke + */ +#ifndef NETWORKIT_AUXILIARY_SPARSE_VECTOR_HPP_ +#define NETWORKIT_AUXILIARY_SPARSE_VECTOR_HPP_ + +#include +#include +#include + +#include + +namespace NetworKit { + +/** + * A vector that imitates a map with unsigned integer keys. + * This class has faster access than a map, but needs space linear in the maximum key value. + */ +template +class SparseVector { +public: + SparseVector(); + + /** + * Construct an empty vector. Empty values are created using the default constructor. + * @param size upper bound for the maximum usable index + */ + explicit SparseVector(index size); + + /** + * Construct an empty vector. + * @param size upper bound for the maximum usable index + * @param emptyValue value used for empty entries + */ + SparseVector(index size, T emptyValue); + + /** + * Resize the vector so that indexes up to size-1 can be used. + */ + void setUpperBound(index size); + + /** * + * @return the upper bound of the indexes that can be used + */ + index upperBound() const; + + /** + * @return the number of inserted elements. + */ + count size() const; + + /** + * Insert a value at a given position. + * @param i index where the value is inserted + * @param value + */ + void insert(index i, T value); + + /** + * Access operator. Before accessing an element, insert it by using the insert() method. + */ + T &operator[](index i); + + /** + * Const access operator. Before accessing an element, insert it by using the insert() method. + */ + const T &operator[](index i) const; + + /** + * Returns true iff an element was previously inserted at the given index. + * @param idx + */ + bool indexIsUsed(index idx); + + /** + * Inserts value at position i, or replaces the value if previously inserted + * @param i + * @param value + */ + void insertOrSet(index i, T value); + + /** + * Remove all indexes for which the value is set to the emptyValue. + */ + void removeUnusedIndexes() { + auto new_end = std::remove_if(usedIndexes.begin(), usedIndexes.end(), + [&](index i) { return data[i] == emptyValue; }); + usedIndexes.erase(new_end, usedIndexes.end()); + } + + /** + * Reset all values to the default value, so it is "empty". The upper bound is not changed. + */ + void reset(); + + /** + * Clear the vector, setting the upper bound of usable indexes to 0. + */ + void clear(); + + /** + * Reallocate the datastructure if size exceeds current upper bound + * This is different from setUpperBound() since we want to make sure both usedIndexes and data + * are allocated on the socket of the calling thread + * @param size + * @param emptyValue new emptyValue + */ + void resize(size_t size, T emptyValue); + + /** + * Applies the given lambda to each inserted index and associated value + * @tparam ElementHandler + * @param lambda + */ + template + void forElements(ElementHandler &&lambda) { + for (index i : usedIndexes) { + lambda(i, data[i]); + } + } + +private: + std::vector data; + std::vector usedIndexes; + T emptyValue; +}; + +template +SparseVector::SparseVector() : emptyValue(T{}) {} + +template +SparseVector::SparseVector(count size) : SparseVector(size, T{}) {} + +template +SparseVector::SparseVector(count size, T emptyValue) + : data(size, emptyValue), emptyValue(emptyValue) {} + +template +void SparseVector::reset() { + for (index i : usedIndexes) { + data[i] = emptyValue; + } + usedIndexes.clear(); +} + +template +void SparseVector::insert(index i, T value) { + assert(data[i] == emptyValue); + usedIndexes.push_back(i); + data[i] = std::move(value); +} + +template +T &SparseVector::operator[](index i) { + return data[i]; +} + +template +const T &NetworKit::SparseVector::operator[](NetworKit::index i) const { + assert(i < data.size()); + return data[i]; +} + +template +void SparseVector::setUpperBound(index size) { + data.resize(size, emptyValue); +} + +template +index SparseVector::upperBound() const { + return data.size(); +} + +template +count SparseVector::size() const { + return usedIndexes.size(); +} + +template +void NetworKit::SparseVector::clear() { + usedIndexes.clear(); + usedIndexes.shrink_to_fit(); + data.clear(); + data.shrink_to_fit(); +} + +template +void NetworKit::SparseVector::resize(size_t size, T emptyValue) { + if (size > upperBound()) { + this->emptyValue = emptyValue; + data = std::vector(size, this->emptyValue); + usedIndexes = std::vector(); + } +} + +template +bool NetworKit::SparseVector::indexIsUsed(index idx) { + return data[idx] != emptyValue; +} + +template +void NetworKit::SparseVector::insertOrSet(NetworKit::index i, T value) { + if (!indexIsUsed(i)) { + insert(i, value); + } else { + data[i] = value; + } +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_AUXILIARY_SPARSE_VECTOR_HPP_ diff --git a/vendor/include/networkit/auxiliary/SpinLock.hpp b/vendor/include/networkit/auxiliary/SpinLock.hpp new file mode 100644 index 0000000..d877236 --- /dev/null +++ b/vendor/include/networkit/auxiliary/SpinLock.hpp @@ -0,0 +1,23 @@ +#ifndef NETWORKIT_AUXILIARY_SPIN_LOCK_HPP_ +#define NETWORKIT_AUXILIARY_SPIN_LOCK_HPP_ + +#include + +namespace Aux { + +class Spinlock { +public: + void lock() { + while (spinner.test_and_set(std::memory_order_acquire)) { + /* spin */ + } + } + void unlock() { spinner.clear(std::memory_order_release); } + +private: + std::atomic_flag spinner = ATOMIC_FLAG_INIT; +}; + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_SPIN_LOCK_HPP_ diff --git a/vendor/include/networkit/auxiliary/StringBuilder.hpp b/vendor/include/networkit/auxiliary/StringBuilder.hpp new file mode 100644 index 0000000..b771bac --- /dev/null +++ b/vendor/include/networkit/auxiliary/StringBuilder.hpp @@ -0,0 +1,322 @@ +#ifndef NETWORKIT_AUXILIARY_STRING_BUILDER_HPP_ +#define NETWORKIT_AUXILIARY_STRING_BUILDER_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Aux { + +template +std::string toString(const T &...args); + +template +std::ostream &printToStream(std::ostream &stream, const T &...args); + +template +std::string toStringF(std::string_view format, const T &...args); + +template +std::ostream &printToStreamF(std::ostream &stream, std::string_view format, const T &...args); + +// Implementation +///////////////// + +namespace Impl { + +// Categories of how a type might be printable +enum class PrintableCategory { + UNPRINTABLE, + ITERATABLE, + PAIR, + TUPLE, + STREAMABLE, + Unprintable = UNPRINTABLE, // this + following added for backwards compatibility + Iteratable = ITERATABLE, + Pair = PAIR, + Tuple = TUPLE, + Streamable = STREAMABLE +}; + +template +constexpr bool isStreamable(); +template +constexpr bool isPair(); +template +constexpr bool isTuple(); +template +constexpr bool isIteratable(); + +template +constexpr PrintableCategory getPrintableCategory() { + return isStreamable() ? PrintableCategory::STREAMABLE + : isPair() ? PrintableCategory::PAIR + : isTuple() ? PrintableCategory::TUPLE + : isIteratable() ? PrintableCategory::ITERATABLE + : + /* else: */ PrintableCategory::UNPRINTABLE; +} +template +struct PrintableCategoryTag {}; +using IteratableTag = PrintableCategoryTag; +using PairTag = PrintableCategoryTag; +using TupleTag = PrintableCategoryTag; +using StreamableTag = PrintableCategoryTag; +using UnprintableTag = PrintableCategoryTag; + +template +void printToStream(std::ostream &stream, const T &, const Args &...); +inline void printToStream(std::ostream &) {} + +template +void printToStreamTagged(std::ostream &stream, const T &, IteratableTag); +template +void printToStreamTagged(std::ostream &stream, const T &, PairTag); +template +void printToStreamTagged(std::ostream &stream, const T &, TupleTag); +template +void printToStreamTagged(std::ostream &stream, const T &, StreamableTag); + +// Claim that this function exists somewhere else to keep the errors clean +// (calling this function is not a problem since the error is already caught earlier +// in printToStream, and calling it directly will result in a linker-error) +template +extern void printToStreamTagged(std::ostream &, const T &, UnprintableTag); + +template +void printToStream(std::ostream &stream, const T &arg, const Args &...args) { + static_assert(getPrintableCategory() != PrintableCategory::UNPRINTABLE, + "printToStream must not be called with an unprintable argument"); + printToStreamTagged(stream, arg, PrintableCategoryTag()>{}); + printToStream(stream, args...); +} + +inline std::tuple +printFormatPartToStream(std::ostream &stream, std::string_view::const_iterator begin, + std::string_view::const_iterator end); + +inline void printToStreamF(std::ostream &stream, std::string_view::const_iterator format_begin, + std::string_view::const_iterator format_end) { + bool printArgument; + using iterator = std::string_view::const_iterator; + iterator it; + std::tie(it, printArgument) = printFormatPartToStream(stream, format_begin, format_end); + if (printArgument) { + throw std::invalid_argument{"formatstring requests more arguments then provided"}; + } +} +template +void printToStreamF(std::ostream &stream, std::string_view::const_iterator format_begin, + std::string_view::const_iterator format_end, const T &arg, + const Args &...args) { + bool printArgument; + using iterator = std::string_view::const_iterator; + iterator it; + std::tie(it, printArgument) = printFormatPartToStream(stream, format_begin, format_end); + if (printArgument) { + printToStream(stream, arg); + printToStreamF(stream, it, format_end, args...); + } else { + assert(it == format_end); + return; + } +} + +/** + * Write the formatstring until the first occurance of "%s" + * to stream, '%%' will be replaced by '%'. + * + * @returns The iterator that points one after the last consumed + * character and whether a further argument should be printed. + */ +inline auto printFormatPartToStream(std::ostream &stream, std::string_view::const_iterator begin, + std::string_view::const_iterator end) + -> std::tuple { + auto it = begin; + while (it != end) { + auto nextPercent = std::find(it, end, '%'); + stream.write(&*it, std::distance(it, nextPercent)); + + if (nextPercent == end) { + it = nextPercent; + break; + } + + it = ++nextPercent; + + if (it == end) { + throw std::invalid_argument{"formatstrings must not end on unmatched '%'"}; + } else if (*it == '%') { + stream.put('%'); + ++it; + } else if (*it == 's') { + ++it; + return std::make_tuple(it, true); + } else { + throw std::invalid_argument{"formatstring contains illegal format-specifier"}; + } + } + assert(it == end); + return std::make_tuple(end, false); +} + +// Brace Yourself: Templatemetaprogramming is coming +//////////////////////////////////////////////////// + +// Iteratable +struct IsIteratableHelper { + static std::false_type isIteratable(...); + + template < + typename T, class Iterator = decltype(std::begin(std::declval())), + AUX_REQUIRE(EndIteratorValid, isSame()))>()), + AUX_REQUIRE(HasInputIterator, + isBaseOrSame::iterator_category>())> + static std::true_type isIteratable(const T &); +}; +template +constexpr bool isIteratable() { + return decltype(IsIteratableHelper::isIteratable(std::declval()))::value; +} + +// Pair +template +struct IsPairHelper : std::false_type {}; +template +struct IsPairHelper> : std::true_type {}; +template +constexpr bool isPair() { + return IsPairHelper::value; +} + +// Tuple +template +struct IsTupleHelper : std::false_type {}; +template +struct IsTupleHelper> : std::true_type {}; +template +constexpr bool isTuple() { + return IsTupleHelper::value; +} + +// Streamable +struct IsStreamableHelper { + static std::false_type isStreamable(...); + + template < + typename T, + typename _streamT = typename std::decay() + << std::declval())>::type, + typename std::enable_if::value + || std::is_base_of::value> * = nullptr> + static std::true_type isStreamable(const T &); +}; +template +constexpr bool isStreamable() { + return decltype(IsStreamableHelper::isStreamable(std::declval()))::value; +} + +// And now: implement the actual printing: +////////////////////////////////////////// + +// Streamable +template +void printToStreamTagged(std::ostream &stream, const T &arg, StreamableTag) { + stream << arg; +} + +// Pair +template +void printToStreamTagged(std::ostream &stream, const T &arg, PairTag) { + stream << '('; + printToStream(stream, arg.first); + stream << ", "; + printToStream(stream, arg.second); + stream << ')'; +} + +// Tuple +template +struct printTupleHelper { + static void print(std::ostream &stream, const Tuple &arg) { + printToStream(stream, std::get(arg)); + stream << ", "; + printTupleHelper::print(stream, arg); + } +}; +template +struct printTupleHelper { + static void print(std::ostream &stream, const Tuple &arg) { + printToStream(stream, std::get(arg)); + } +}; +template +void printToStreamTagged(std::ostream &stream, const T &arg, TupleTag) { + stream << '('; + printTupleHelper::value>::print(stream, arg); + stream << ')'; +} + +// Iteratable +template +void printToStreamTagged(std::ostream &stream, const T &arg, IteratableTag) { + auto it = std::begin(arg); + auto end = std::end(arg); + bool firstpass = true; + stream << '['; + while (it != end) { + if (firstpass) { + firstpass = false; + } else { + stream << ", "; + } + printToStream(stream, *it); + ++it; + } + stream << ']'; +} + +} // namespace Impl + +// Finally: put together the public interface: +////////////////////////////////////////////// + +template +std::string toString(const T &...args) { + std::stringstream stream; + printToStream(stream, args...); + return stream.str(); +} + +template +std::ostream &printToStream(std::ostream &stream, const T &...args) { + Impl::printToStream(stream, args...); + return stream; +} + +template +std::string toStringF(std::string_view format, const T &...args) { + std::stringstream stream; + printToStreamF(stream, format, args...); + return stream.str(); +} + +template +std::ostream &printToStreamF(std::ostream &stream, std::string_view format, const T &...args) { + Impl::printToStreamF(stream, format.begin(), format.end(), args...); + return stream; +} + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_STRING_BUILDER_HPP_ diff --git a/vendor/include/networkit/auxiliary/StringTools.hpp b/vendor/include/networkit/auxiliary/StringTools.hpp new file mode 100644 index 0000000..f104684 --- /dev/null +++ b/vendor/include/networkit/auxiliary/StringTools.hpp @@ -0,0 +1,76 @@ +/* + * StringTools.hpp + * + * Completely rewritten on: 12.05.2014 + * Author: Florian Weber (uagws@student.kit.edu) + */ + +#ifndef NETWORKIT_AUXILIARY_STRING_TOOLS_HPP_ +#define NETWORKIT_AUXILIARY_STRING_TOOLS_HPP_ + +#include +#include +#include +#include + +namespace Aux { + +/** + * Missing string functions. + */ +namespace StringTools { + +/** + * Splits a range of characters at a delimiter into a vector of strings. + * + * Requirements: + * Character must be equality-comparable to char and it must be possible to construct a char from + * any Character. + * Iterator must be an input-iterator over Characters. + */ +template +std::vector split(Iterator begin, Iterator end, Character delim = Character{' '}) { + + // measurements showed that precalculating the number of tokens and + // reserving space for them was in fact slower than just letting + // the vector grow naturally. + std::vector tokens; + + auto it = begin; + while (it != end) { + auto tmp = std::find(it, end, delim); + tokens.emplace_back(it, tmp); + if (tmp == end) { + break; + } + it = tmp; + ++it; + } + return tokens; +} + +/** + * Split a string at delimiter and return vector of parts. + */ +inline std::vector split(std::string_view s, char delim = ' ') { + return split(s.begin(), s.end(), delim); +} + +/** + * Determines whether @a str ends with @a suffix. + */ +inline bool ends_with(std::string_view str, std::string_view suffix) { + return str.size() >= suffix.size() + && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; +} + +/** + * Determines whether @a str starts with @a prefix. + */ +inline bool starts_with(std::string_view str, std::string_view prefix) { + return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0; +} + +} /* namespace StringTools */ +} /* namespace Aux */ +#endif // NETWORKIT_AUXILIARY_STRING_TOOLS_HPP_ diff --git a/vendor/include/networkit/auxiliary/TemplateUtils.hpp b/vendor/include/networkit/auxiliary/TemplateUtils.hpp new file mode 100644 index 0000000..4fc9653 --- /dev/null +++ b/vendor/include/networkit/auxiliary/TemplateUtils.hpp @@ -0,0 +1,76 @@ +#ifndef NETWORKIT_AUXILIARY_TEMPLATE_UTILS_HPP_ +#define NETWORKIT_AUXILIARY_TEMPLATE_UTILS_HPP_ + +#include + +/** + * The macro makes the use of std::enable_if much easier by removing all the boilerplate. + * + * The 'what' argument must be a valid identifier that describes, what is required. + * Example: you want to require that T is an integer, than what should be something like + * T_is_integer + * + * The second argument must be a constant boolean expression. In order to allow templates that + * would otherwise confuse the preprocessor, this is passed as variadic argument (this is however + * an implementation detail and you should never actually pass more than one argument. + */ +#define AUX_REQUIRE(what, ...) class what = typename ::std::enable_if<__VA_ARGS__>::type + +/** + * If two templates only differ in the default-values of their template-arguments + * C++ considers this to be a compilation-error. A simple way to prevent this is to + * add further defaulted template-arguments, which is what this macro provides in a + * semantic way. + * + * Example: + * + * template + * void fun(T) {...} + * + * template + * void fun(T) {...} + * + * Note however that it may often be a cleaner solution to use compile-time dispatching instead + * of hacks that envolve enable-if. + */ +#define AUX_DUMMY_ARGUMENT class = void + +namespace Aux { + +/** + * This is a backport of C++14 std::decay_t + */ +template +using decay_t = typename std::decay::type; + +/** + * Returns the corresponding std::integral_constant to a boolean + * value B. + */ +template +using boolToType = std::integral_constant; + +/** + * This is just a wrapper around std::is_same in order to provide a nicer interface. + * + * With C++14 this could use template-variables, but with C++11 we are stuck with + * constexpr-functions. + */ +template +constexpr bool isSame() { + return std::is_same::value; +} + +/** + * Checks whether Derived is either a type that derives from Base or is identical to Base. + * + * This is very usefull for situations in which you work with iterator-traits or the like. + */ +template +constexpr bool isBaseOrSame() { + return isSame() || std::is_base_of::value; +} + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_TEMPLATE_UTILS_HPP_ diff --git a/vendor/include/networkit/auxiliary/Timer.hpp b/vendor/include/networkit/auxiliary/Timer.hpp new file mode 100644 index 0000000..1a5d328 --- /dev/null +++ b/vendor/include/networkit/auxiliary/Timer.hpp @@ -0,0 +1,145 @@ +/* + * Timer.hpp + * + * Created on: 14.01.2013 + * Author: Christian Staudt (christian.staudt@kit.edu) + */ + +#ifndef NETWORKIT_AUXILIARY_TIMER_HPP_ +#define NETWORKIT_AUXILIARY_TIMER_HPP_ + +#include +#include +#include + +#include + +namespace Aux { + +/** + * A timer for running time measurements. + */ +class Timer { +public: +#ifdef __MIC__ + using my_steady_clock = std::chrono::monotonic_clock; +#else + using my_steady_clock = std::chrono::steady_clock; +#endif // __MIC__ + + Timer() = default; + + /** + * Start the clock. + * Returns the time at which the instance was started. + */ + my_steady_clock::time_point start() noexcept; + + /** + * Stops the clock permanently for the instance of the Timer. + * Returns the time at which the instance was stopped. + */ + my_steady_clock::time_point stop() noexcept; + + /** + * Returns a chrono::duration since the Timer was started. + * If stop() was called, the duration is between the start() and stop() + * calls is returned. + */ + std::chrono::duration elapsed() const noexcept; + + /** + * Returns the number of milliseconds since the Timer was started. + * If stop() was called, the duration is between the start() and stop() + * calls is returned. + */ + uint64_t elapsedMilliseconds() const noexcept; + + /** + * Returns the number of microseconds since the Timer was started. + * If stop() was called, the duration is between the start() and stop() + * calls is returned. + */ + uint64_t elapsedMicroseconds() const noexcept; + + /** + * Returns the number of nanoseconds since the Timer was started. + * If stop() was called, the duration is between the start() and stop() + * calls is returned. + */ + uint64_t elapsedNanoseconds() const noexcept; + + /** + * Returns the time at which the instance was started. + */ + my_steady_clock::time_point startTime() const noexcept; + + /** + * Returns the time at which the instance was stopped. + */ + my_steady_clock::time_point stopTime() const noexcept; + + /** + * Returns a human-readable representation including the elapsed time and unit. + */ + std::string elapsedTag() const; + +protected: + bool running{false}; //!< true if timer has been started and not stopped after that + my_steady_clock::time_point started; //!< time at which timer has been started + my_steady_clock::time_point stopped; //!< time at which timer has been stopped + + /// If running returns now, otherwise the stop time + my_steady_clock::time_point stopTimeOrNow() const noexcept; +}; + +/** + * A timer for running time measurements. + * Same as Timer but automatically starts on construction. + */ +class StartedTimer : public Timer { +public: + StartedTimer() : Timer() { start(); } +}; + +/** + * A timer for running time measurements within a scope. + * + * Same as Timer but automatically starts on construction and report on destruction. + * + * @code + * { + * Aux::ScopedTimer("Algorithm A"); // WRONG; will directly report without measuring the scope + * Aux::ScopedTimer someName("Algorithm B"); // OK: the named instance is valid until the end of + * the scope + * // some expensive operations + * + * + * } // <- Report time since creation of the timer object via Aux::Log + * @endcode + * + * @warning + * As the timer exploits RAII, it requires a named instance to extend its life time until the + * end of the current scope. In the example above "someName" is used. If the time measured seems + * too short, make you created a named instances. + */ +class LoggingTimer : public Timer { +public: + /** + * @param label The label printed out next to the measurement + * @param level Only measure if logging at the provided LogLevel is enabled during runtime. + * If logging at the given level is disable the Timer is very cheap to construct. + * If logging is disabled during construction or destruction, no message is shown. + */ + explicit LoggingTimer(std::string_view label = "", + Aux::Log::LogLevel level = Aux::Log::LogLevel::DEBUG); + ~LoggingTimer(); + +private: + Aux::Log::LogLevel level; + std::string label; +}; + +} /* namespace Aux */ + +#endif // NETWORKIT_AUXILIARY_TIMER_HPP_ diff --git a/vendor/include/networkit/auxiliary/VectorComparator.hpp b/vendor/include/networkit/auxiliary/VectorComparator.hpp new file mode 100644 index 0000000..b6a0232 --- /dev/null +++ b/vendor/include/networkit/auxiliary/VectorComparator.hpp @@ -0,0 +1,32 @@ + +#ifndef NETWORKIT_AUXILIARY_VECTOR_COMPARATOR_HPP_ +#define NETWORKIT_AUXILIARY_VECTOR_COMPARATOR_HPP_ + +#include +#include + +namespace Aux { + +// Implementation of vector-based comparators + +template +struct LessInVector { + LessInVector(const std::vector &vec) : vec(&vec) {} + bool operator()(uint64_t x, uint64_t y) const noexcept { return (*vec)[x] < (*vec)[y]; } + +private: + const std::vector *vec; +}; + +template +struct GreaterInVector { + GreaterInVector(const std::vector &vec) : vec(&vec) {} + bool operator()(uint64_t x, uint64_t y) const noexcept { return (*vec)[x] > (*vec)[y]; } + +private: + const std::vector *vec; +}; + +} // namespace Aux + +#endif // NETWORKIT_AUXILIARY_VECTOR_COMPARATOR_HPP_ diff --git a/vendor/include/networkit/base/Algorithm.hpp b/vendor/include/networkit/base/Algorithm.hpp new file mode 100644 index 0000000..0493ad3 --- /dev/null +++ b/vendor/include/networkit/base/Algorithm.hpp @@ -0,0 +1,41 @@ + +#ifndef NETWORKIT_BASE_ALGORITHM_HPP_ +#define NETWORKIT_BASE_ALGORITHM_HPP_ + +#include +#include + +namespace NetworKit { + +class Algorithm { +protected: + bool hasRun = false; + +public: + virtual ~Algorithm() = default; + + /** + * The generic run method which calls runImpl() and takes care of setting @ref hasRun to the + * appropriate value. + */ + virtual void run() = 0; + + /** + * Indicates whether an algorithm has completed computation or not. + * + * @return The value of @ref hasRun. + */ + bool hasFinished() const noexcept { return hasRun; } + + /** + * Assure that the algorithm has been run, throws a std::runtime_error otherwise. + */ + void assureFinished() const { + if (!hasRun) + throw std::runtime_error("Error, run must be called first"); + } +}; + +} // namespace NetworKit + +#endif // NETWORKIT_BASE_ALGORITHM_HPP_ diff --git a/vendor/include/networkit/base/DynAlgorithm.hpp b/vendor/include/networkit/base/DynAlgorithm.hpp new file mode 100644 index 0000000..4a2039f --- /dev/null +++ b/vendor/include/networkit/base/DynAlgorithm.hpp @@ -0,0 +1,31 @@ +#ifndef NETWORKIT_BASE_DYN_ALGORITHM_HPP_ +#define NETWORKIT_BASE_DYN_ALGORITHM_HPP_ + +#include +#include +#include + +namespace NetworKit { + +class DynAlgorithm { + +public: + /** + * Virtual default destructor + */ + virtual ~DynAlgorithm() = default; + + /** + * The generic update method for updating data structure after an update. + */ + virtual void update(GraphEvent e) = 0; + + /** + * The generic update method for updating data structure after a batch of updates. + */ + virtual void updateBatch(const std::vector &batch) = 0; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_BASE_DYN_ALGORITHM_HPP_ diff --git a/vendor/include/networkit/centrality/ApproxBetweenness.hpp b/vendor/include/networkit/centrality/ApproxBetweenness.hpp new file mode 100644 index 0000000..3bd7792 --- /dev/null +++ b/vendor/include/networkit/centrality/ApproxBetweenness.hpp @@ -0,0 +1,62 @@ +/* + * ApproxBetweenness.hpp + * + * Created on: 09.04.2014 + * Author: cls + */ + +#ifndef NETWORKIT_CENTRALITY_APPROX_BETWEENNESS_HPP_ +#define NETWORKIT_CENTRALITY_APPROX_BETWEENNESS_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Approximation of betweenness centrality according to algorithm described in + * Matteo Riondato and Evgenios M. Kornaropoulos: Fast Approximation of Betweenness Centrality + * through Sampling + */ +class ApproxBetweenness final : public Centrality { + +public: + /** + * The algorithm approximates the betweenness of all vertices so that the scores are + * within an additive error @a epsilon with probability at least (1- @a delta). + * The values are normalized by default. The run() method takes O(m) time per sample, where m + * is the number of edges of the graph. The number of samples is proportional to + * universalConstant/epsilon^2. Although this algorithm has a theoretical guarantee, the + * algorithm implemented in Estimate Betweenness usually performs better in practice Therefore, + * we recommend to use EstimateBetweenness if no theoretical guarantee is needed. + * + * @param G the graph + * @param epsilon maximum additive error + * @param delta probability that the values are within the error guarantee + * @param universalConstant the universal constant to be used in + * computing the sample size. It is 1 by default. Some references suggest + * using 0.5, but there is no guarantee in this case. + */ + ApproxBetweenness(const Graph &G, double epsilon = 0.01, double delta = 0.1, + double universalConstant = 1.0); + + /** + * Computes betweenness approximation on the graph passed in constructor. + */ + void run() override; + + /** + * @return number of samples taken in last run + */ + count numberOfSamples() const; + +private: + const double epsilon; + const double delta; + count r; // number of samples taken in last run + double universalConstant; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_APPROX_BETWEENNESS_HPP_ diff --git a/vendor/include/networkit/centrality/ApproxCloseness.hpp b/vendor/include/networkit/centrality/ApproxCloseness.hpp new file mode 100644 index 0000000..04696e7 --- /dev/null +++ b/vendor/include/networkit/centrality/ApproxCloseness.hpp @@ -0,0 +1,136 @@ +/* + * ApproxCloseness.hpp + * + * Created on: Dec 8, 2015 + * Author: Sarah Lutteropp (uwcwa@student.kit.edu) and Michael Wegner + * (michael.wegner@student.kit.edu) + */ + +#ifndef NETWORKIT_CENTRALITY_APPROX_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_APPROX_CLOSENESS_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Approximation of closeness centrality according to algorithm described in + * Cohen et al., Computing Classic Closeness Centrality, at Scale + */ +class ApproxCloseness : public Centrality { + +public: + enum ClosenessType { INBOUND, OUTBOUND, SUM }; + + using CLOSENESS_TYPE = ClosenessType; // enum alias for backwards compatibility + + /** + * Constructs an instance of the ApproxCloseness class for @a graph using @a nSamples during the + * run() method. The @a epsilon parameter (standard = 0.1) is used to control the switch between + * sampling and pivoting. Using @a epsilon = 0, the algorithm only uses sampling. (see Cohen, + * Edith, et al. "Computing classic closeness centrality, at scale." Proceedings of the second + * ACM conference on Online social networks. ACM, 2014.). The running time is proportional to + * nSamples * m, where m is the number of edges. Notice: the input graph has to be connected. + * @param graph input graph + * @param nSamples user defined number of samples + * @param epsilon Value in [0, infty) controlling the switch between sampling and + * pivoting. When using 0, only sampling is used. Standard is 0.1. + * @param normalized normalize centrality values in interval [0,1] + * @param type use in- or outbound centrality or the sum of both (see paper) for + * computing closeness on directed graph. If G is undirected, this can be ignored. + */ + ApproxCloseness(const Graph &G, count nSamples, double epsilon = 0.1, bool normalized = false, + CLOSENESS_TYPE type = OUTBOUND); + + /** + * Computes closeness approximation on the graph passed in constructor. + */ + void run() override; + + /** + * Returns the maximum possible Closeness a node can have in a graph with the same amount of + * nodes (=a star) + */ + double maximum() override; + + /** + * @return The square error when closeness centrality has been computed for an undirected graph. + */ + std::vector getSquareErrorEstimates(); + +private: + count nSamples; + double epsilon; + + /** \sum_{i \in L(j) \cap C} d_{ji} for every j \in V */ + std::vector LCSum; + + /** |L(j) \cap C| for every j \in V */ + std::vector LCNum; + + /** \sum_{i \in L(j) \cap C} d_{ji}^2 for every j \in V */ + std::vector LCSumSQ; + + /** \sum_{i \in HC(j)} d_{ji} for every j \in V */ + std::vector HCSum; + + /** \frac{1}{|HC(j)|} * \sum_{i \in HC(j)} (d_{ij} - d_{c(j)j})^2 for every j \in V */ + std::vector HCSumSQErr; + + /** \sum_{i \in H(j)} d_{c(j)i} for every j \in V */ + std::vector HSum; + + /** |H(j)| for every j \in V */ + std::vector HNum; + + /** Reachability estimation **/ + std::vector R; + + std::vector SQErrEst; + + // divided by two s.t. infDist + infDist produces no overflow + const edgeweight infDist = std::floor(std::numeric_limits::max() / 2.0); + + ClosenessType type = ApproxCloseness::ClosenessType::OUTBOUND; + + void estimateClosenessForUndirectedGraph(); + void estimateClosenessForDirectedGraph(bool outbound); + inline void computeClosenessForDirectedWeightedGraph(bool outbound); + inline void computeClosenessForDirectedUnweightedGraph(bool outbound); + + /** + * Runs a multi-source Dijkstra from all @a samples and sets the closest pivot and the distance + * from it for every node in G. + * @param samples The sampled nodes that are the pivot nodes. + * @param pivot[out] Stores the closest pivot (sample) from every node. + * @param delta[out] Stores the distance d(u,pivot(u)) for every node u. + */ + void computeClosestPivot(const std::vector &samples, std::vector &pivot, + std::vector &delta); + + /** + * Runs the algorithm of Cohen et al. for a single pivot. + * @param i + * @param pivot + * @param delta + * @param samples + */ + void runOnPivot(index i, const std::vector &pivot, const std::vector &delta, + const std::vector &samples); + + /** + * Orders the nodes of G in increasing distance from @a pivot. The distances from @a pivot are + * stored in @a pivotDist + * @param pivot + * @param order[out] + * @param pivotDist[out] + */ + void orderNodesByIncreasingDistance(node pivot, std::vector &order, + std::vector &pivotDist); +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_APPROX_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/centrality/ApproxElectricalCloseness.hpp b/vendor/include/networkit/centrality/ApproxElectricalCloseness.hpp new file mode 100644 index 0000000..66bc3e2 --- /dev/null +++ b/vendor/include/networkit/centrality/ApproxElectricalCloseness.hpp @@ -0,0 +1,156 @@ +/* + * ApproxElectricalCloseness.hpp + * + * Created on: 17.10.2019 + * Authors: Eugenio Angriman + * Alexander van der Grinten + */ + +#ifndef NETWORKIT_CENTRALITY_APPROX_ELECTRICAL_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_APPROX_ELECTRICAL_CLOSENESS_HPP_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class ApproxElectricalCloseness final : public Centrality { + +public: + /** + * Approximates the electrical closeness of all the vertices of the graph by approximating the + * diagonal of the laplacian's pseudoinverse of @a G. Every element of the diagonal is + * guaranteed to have a maximum absolute error of @a epsilon. Based on "Approximation of the + * Diagonal of a Laplacian’s Pseudoinverse for Complex Network Analysis", Angriman et al., ESA + * 2020. The algorithm does two steps: solves a linear system and samples uniform spanning trees + * (USTs). The parameter @a kappa balances the tolerance of solver for the linear system and the + * number of USTs to be sampled. A high value of @a kappa raises the tolerance (solver converges + * faster) but more USTs need to be sampled, vice versa for a low value of @a kappa. + * + * @param G The input graph. + * @param epsilon Maximum absolute error of the elements in the diagonal. + * @param kappa Balances the tolerance of the solver for the linear system and the number of + * USTs to be sampled. + */ + ApproxElectricalCloseness(const Graph &G, double epsilon = 0.1, double kappa = 0.3); + + ~ApproxElectricalCloseness() override = default; + + /** + * Run the algorithm. + */ + void run() override; + + /** + * Return an epsilon-approximation of the diagonal of the laplacian's pseudoinverse. + * + * @return Approximation of the diagonal of the laplacian's pseudoinverse. + */ + const std::vector &getDiagonal() const { + assureFinished(); + return diagonal; + } + + /** + * Compute and return the nearly-exact values of the diagonal of the laplacian's pseudoinverse. + * The values are computed by solving Lx = e_u - 1 / n for every vertex u of the graph with a + * LAMG solver. + * + * @param tol Tolerance for the LAMG solver. + * + * @return Nearly-exact values of the diagonal of the laplacian's pseudoinverse. + */ + std::vector computeExactDiagonal(double tol = 1e-9) const; + +private: + const double epsilon, delta, kappa; + node root = 0; + count rootEcc; + + // #of BFSs used to estimate a vertex with low eccentricity. + static constexpr uint32_t sweeps = 10; + + enum class NodeStatus : unsigned char { + NOT_IN_COMPONENT, + IN_SPANNING_TREE, + NOT_VISITED, + VISITED + }; + + // Used to mark the status of each node, one vector per thread + std::vector> statusGlobal; + + std::unique_ptr bccPtr; + + // Nodes in each biconnected components sorted by their degree. + std::vector> sequences; + + // Pointers to the parent of the UST, one vector per thread + std::vector> parentGlobal; + + // Index of the parent component of the current component (after the topological order has been + // determined) + std::vector biParent; + // Node within the biconnected component that points to the node in the parent component + std::vector biAnchor; + + // Topological order of the biconnected components + std::vector topOrder; + + // Non-normalized approx effective resistance, one per thread. + // Values could be negative, so we use signed integers. + std::vector> approxEffResistanceGlobal; + + // Pseudo-inverse diagonal + std::vector diagonal; + + // Timestamps for DFS + std::vector> tVisitGlobal, tFinishGlobal; + + // Random number generators + std::vector generators; + std::vector> degDist; + + // Parent pointers of the bfs tree + std::vector bfsParent; + + // Nodes sequences: Wilson's algorithm runs faster if we start the random walks following a + // specific sequence of nodes. In this function we compute those sequences. + void computeNodeSequence(); + + // Adjacency list for trees: additional data structure to speed-up the DFS + std::vector> ustChildPtrGlobal; + std::vector> ustSiblingPtrGlobal; + + void computeBFSTree(); + void sampleUST(); + void dfsUST(); + void aggregateUST(); + + node approxMinEccNode(); + + count computeNumberOfUSTs() const; + +#ifdef NETWORKIT_SANITY_CHECKS + // Debugging methods + void checkBFSTree() const; + void checkUST() const; + void checkTwoNodesSequence(const std::vector &sequence) const; + void checkTimeStamps() const; +#endif // NETWORKIT_SANITY_CHECKS +}; + +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_APPROX_ELECTRICAL_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/centrality/ApproxGroupBetweenness.hpp b/vendor/include/networkit/centrality/ApproxGroupBetweenness.hpp new file mode 100644 index 0000000..d5b5da9 --- /dev/null +++ b/vendor/include/networkit/centrality/ApproxGroupBetweenness.hpp @@ -0,0 +1,124 @@ +/* + * ApproxGroupBetweenness.hpp + * + * Created on: 13.03.2018 + * Author: Marvin Pogoda + */ +#ifndef NETWORKIT_CENTRALITY_APPROX_GROUP_BETWEENNESS_HPP_ +#define NETWORKIT_CENTRALITY_APPROX_GROUP_BETWEENNESS_HPP_ + +#include +#include + +#include +#include +#include + +namespace NetworKit { + +class ApproxGroupBetweenness final : public Algorithm { + +public: + /** Constructs the ApproxGroupBetweenness class for a given undirected graph + * @a G. + * @param groupSize Size of the set of nodes. + * @aram epsilon Determines the accuracy of the approximation. + */ + ApproxGroupBetweenness(const Graph &G, count groupSize, double epsilon); + + /** + * Approximately computes a set of nodes with maximum groupbetweenness. Based + * on the algorithm of Mahmoody,Tsourakakis and Upfal. + */ + void run() override; + + /** + * Returns a vector of nodes containing the set of nodes with approximated + * maximum group betweenness. + */ + std::vector groupMaxBetweenness() const; + + /** + * Returns the score of the given set. + */ + double scoreOfGroup(const std::vector &S, bool normalized = false) const; + +protected: + const Graph &G; + count n; + std::vector maxGroup; + const count groupSize; + const double epsilon; +}; + +inline std::vector ApproxGroupBetweenness::groupMaxBetweenness() const { + assureFinished(); + return maxGroup; +} + +inline double ApproxGroupBetweenness::scoreOfGroup(const std::vector &S, + const bool normalized) const { + if (S.empty()) + throw std::runtime_error("Error: input group is empty"); + + count z = G.upperNodeIdBound(); + std::vector inGroup(z); + for (node u : S) { + if (!G.hasNode(u)) + throw std::runtime_error("Error, input group contains nodes not in the graph"); + if (inGroup[u]) + WARN("Input group contains duplicate nodes!"); + inGroup[u] = true; + } + + std::vector scorePerThread(omp_get_max_threads()); + std::vector> deps(omp_get_max_threads(), std::vector(n)); + std::vector bfss(omp_get_max_threads(), BFS(G, 0, true, true)); + + auto computeDeps = [&](node source) { + auto &dep = deps[omp_get_thread_num()]; + std::ranges::fill(dep, 0); + + BFS &bfs = bfss[omp_get_thread_num()]; + bfs.setSource(source); + bfs.run(); + + double weight; + auto sortedNodes = bfs.getNodesSortedByDistance(); + for (auto it = sortedNodes.rbegin(); it != sortedNodes.rend(); ++it) { + node target = *it; + for (node pred : bfs.getPredecessors(target)) { + (bfs.numberOfPaths(pred) / bfs.numberOfPaths(target)).ToDouble(weight); + if (inGroup[pred]) { + if (pred != source) { + scorePerThread[omp_get_thread_num()] += + dep[pred] + weight * (1 + dep[target]); + } + } else { + dep[pred] += weight * (1 + dep[target]); + } + } + } + }; + + G.balancedParallelForNodes(computeDeps); + + double result = 0; + for (double curScore : scorePerThread) + result += curScore; + + if (normalized) { + double nPairs = static_cast((z - S.size()) * (z - S.size() - 1)); + if (nPairs <= 0) + return 0; + if (!G.isDirected()) + nPairs /= 2; + result /= nPairs; + } + + return result; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_APPROX_GROUP_BETWEENNESS_HPP_ diff --git a/vendor/include/networkit/centrality/ApproxSpanningEdge.hpp b/vendor/include/networkit/centrality/ApproxSpanningEdge.hpp new file mode 100644 index 0000000..338f28c --- /dev/null +++ b/vendor/include/networkit/centrality/ApproxSpanningEdge.hpp @@ -0,0 +1,84 @@ +/* + * ApproxSpanningEdge.hpp + * + * Created on: 29.09.2019 + * Authors: Eugenio Angriman + * + */ + +#ifndef NETWORKIT_CENTRALITY_APPROX_SPANNING_EDGE_HPP_ +#define NETWORKIT_CENTRALITY_APPROX_SPANNING_EDGE_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class ApproxSpanningEdge final : public Algorithm { + + enum class NodeStatus : unsigned char { + NOT_IN_COMPONENT, + IN_SPANNING_TREE, + IN_RANDOM_WALK, + NOT_VISITED + }; + +public: + /** + * Computes an epsilon-approximation of the spanning edge centrality of every edge of the input + * graph with probability (1 - 1/n), based on "Efficient Algorithms for Spanning Tree + * Centrality", Hayashi et al., IJCAI, 2016. This implementation also supports multi-threading. + * + * @param G An undirected graph. + * @param eps Maximum additive error. + */ + ApproxSpanningEdge(const Graph &G, double eps = 0.1); + + ~ApproxSpanningEdge() override = default; + + /** + * Executes the algorithm. + */ + void run() override; + + /** + * Return the spanning edge approximation for each edge of the graph. + * + * @return Spanning edge approximation for each edge of the input graph. + */ + std::vector scores() const; + +private: + const Graph &G; + double eps; + double delta; + count nSamples; + + // For each thread, marks which nodes have been visited by the random walk. + std::vector> visitedNodes; + + // For each thread, counts how many times each edge appears in a random + // spanning tree. + std::vector> edgeScores; + + // Sequence of biconnected components. + std::vector> sequences; + + // Parent pointers. + std::vector> parents; + + // Ids of edge connecting the nodes to their parents. + std::vector> parentsEdgeIds; + + // Samples a spanning tree uniformly at random. + void sampleUST(); +}; + +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_APPROX_SPANNING_EDGE_HPP_ diff --git a/vendor/include/networkit/centrality/Betweenness.hpp b/vendor/include/networkit/centrality/Betweenness.hpp new file mode 100644 index 0000000..b741fc0 --- /dev/null +++ b/vendor/include/networkit/centrality/Betweenness.hpp @@ -0,0 +1,47 @@ +/* + * Betweenness.hpp + * + * Created on: 19.02.2014 + * Author: cls, ebergamini + */ + +#ifndef NETWORKIT_CENTRALITY_BETWEENNESS_HPP_ +#define NETWORKIT_CENTRALITY_BETWEENNESS_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class Betweenness final : public Centrality { +public: + /** + * Constructs the Betweenness class for the given Graph @a G. If the betweenness scores should + * be normalized, then set @a normalized to true. The run() method takes O(nm) + * time, where n is the number of nodes and m is the number of edges of the graph. + * + * @param G The graph. + * @param normalized Set this parameter to true if scores should be normalized in + * the interval [0,1]. + * @param computeEdgeCentrality Set this parameter to true if edge betweenness + * should be computed as well. + */ + Betweenness(const Graph &G, bool normalized = false, bool computeEdgeCentrality = false); + + /** + * Computes betweenness scores on the graph passed in constructor. + */ + void run() override; + + /* + * Returns the maximum possible Betweenness a node can have in a graph with the same amount of + * nodes (=a star) + */ + double maximum() override; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_BETWEENNESS_HPP_ diff --git a/vendor/include/networkit/centrality/Centrality.hpp b/vendor/include/networkit/centrality/Centrality.hpp new file mode 100644 index 0000000..38c8114 --- /dev/null +++ b/vendor/include/networkit/centrality/Centrality.hpp @@ -0,0 +1,98 @@ +/* + * Centrality.hpp + * + * Created on: 19.02.2014 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_CENTRALITY_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_CENTRALITY_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Abstract base class for centrality measures. + */ +class Centrality : public Algorithm { +public: + /** + * Constructs the Centrality class for the given Graph @a G. If the centrality scores should be + * normalized, then set @a normalized to @c true. + * + * @param G The graph. + * @param normalized If set to @c true the scores are normalized in the interval [0,1]. + * @param computeEdgeCentrality If true, compute also edge centralities (for algorithms + * where this is applicable) + */ + Centrality(const Graph &G, bool normalized = false, bool computeEdgeCentrality = false); + + /** + * Computes centrality scores on the graph passed in constructor. + */ + void run() override = 0; + + /** + * Get a vector containing the centrality score for each node in the graph. + * + * @return The centrality scores calculated by @ref run(). + */ + virtual const std::vector &scores() const; + + /** + * Get a vector containing the edge centrality score for each edge in the graph (where + * applicable). + * @return The edge betweenness scores calculated by @ref run(). + */ + virtual std::vector edgeScores(); + + /** + * Get a vector of pairs sorted into descending order. Each pair contains a node and the + * corresponding score calculated by @ref run(). + * @return A vector of pairs. + */ + virtual std::vector> ranking(); + + /** + * Get the centrality score of node @a v calculated by @ref run(). + * + * @param v A node. + * @return The betweenness score of node @a v. + */ + virtual double score(node v); + + /** + * Get the theoretical maximum of centrality score in the given graph. + * + * @return The maximum centrality score. + */ + virtual double maximum(); + + /** + * Compute the centralization of a network with respect to some centrality measure. + + * The centralization of any network is a measure of how central its most central + * node is in relation to how central all the other nodes are. + * Centralization measures then (a) calculate the sum in differences + * in centrality between the most central node in a network and all other nodes; + * and (b) divide this quantity by the theoretically largest such sum of + * differences in any network of the same size. + + * @return centrality index + */ + virtual double centralization(); + +protected: + const Graph &G; + std::vector scoreData; + std::vector edgeScoreData; + bool normalized; // true if scores should be normalized in the interval [0,1] + bool computeEdgeCentrality; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/Closeness.hpp b/vendor/include/networkit/centrality/Closeness.hpp new file mode 100644 index 0000000..148e562 --- /dev/null +++ b/vendor/include/networkit/centrality/Closeness.hpp @@ -0,0 +1,107 @@ +/* + * Closeness.hpp + * + * Created on: 03.10.2014 + * Authors: nemes, + * Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_CLOSENESS_HPP_ + +#include +#include + +#include + +namespace NetworKit { + +enum ClosenessVariant { + STANDARD = 0, + GENERALIZED = 1, + standard = STANDARD, // this + following added for backwards compatibility + generalized = GENERALIZED +}; + +/** + * @ingroup centrality + */ +class Closeness : public Centrality { + +public: + /** + * Constructs the Closeness class for the given Graph @a G. If the closeness + * scores should be normalized, then set @a normalized to true. + * The run() method takes O(nm) time, where n is the number of nodes and m + * is the number of edges of the graph. NOTICE: the graph has to be + * connected. + * + * @param G The graph. + * @param normalized Set this parameter to false if scores + * should not be normalized into an interval of [0, 1]. Normalization only + * for unweighted graphs. + * + */ + Closeness(const Graph &G, bool normalized, + ClosenessVariant variant = ClosenessVariant::STANDARD); + + /** + * Old constructor, we keep it for backward compatibility. It computes the + * standard variant of the closenes. + * + * @param G The graph. + * @param normalized Set this parameter to false if scores + * should not be normalized into an interval of [0, 1]. Normalization only + * for unweighted graphs. + * @param checkConnectedness turn this off if you know the graph is + * connected. + * + */ + Closeness(const Graph &G, bool normalized = true, bool checkConnectedness = true); + + /** + * Computes closeness cetrality on the graph passed in constructor. + */ + void run() override; + + /* + * Returns the maximum possible Closeness a node can have in a graph with + * the same amount of nodes (=a star) + */ + double maximum() override { + return normalized ? 1. : (1. / (static_cast(G.upperNodeIdBound() - 1))); + } + +private: + ClosenessVariant variant; + std::vector> uDist; + std::vector> dDist; + std::vector> visited; + std::vector ts; + + void checkConnectedComponents() const; + void bfs(); + void dijkstra(); + void incTS(); + void updateScoreData(node u, count reached, double sum) { + if (sum > 0) { + if (variant == ClosenessVariant::STANDARD) { + scoreData[u] = 1.0 / sum; + } else { + scoreData[u] = static_cast(reached - 1) / sum + / static_cast(G.numberOfNodes() - 1); + } + } else { + scoreData[u] = 0.; + } + if (normalized) + scoreData[u] *= + (variant == ClosenessVariant::STANDARD ? G.numberOfNodes() : reached) - 1.; + } + + std::vector>> heaps; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/centrality/ComplexPaths.hpp b/vendor/include/networkit/centrality/ComplexPaths.hpp new file mode 100644 index 0000000..5074276 --- /dev/null +++ b/vendor/include/networkit/centrality/ComplexPaths.hpp @@ -0,0 +1,113 @@ +/* + * ComplexPaths.hpp + * + * + * Created on:16.06.2023 + * Author: Klaus Ahrens + * + * + * adapted and reimplemented from + * + * https://github.com/drguilbe/complexpaths.git + * + * see [ Guilbeault, D., Centola, D. Topological measures for + * identifying and predicting the spread of complex contagions. + * Nat Commun 12, 4430 (2021). + * https://doi.org/10.1038/s41467-021-24704-6 ] + * + */ + +#ifndef NETWORKIT_CENTRALITY_COMPLEX_PATHS_HPP_ +#define NETWORKIT_CENTRALITY_COMPLEX_PATHS_HPP_ + +#include +#include + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * computes + * in Mode::singleNode : + * complex path graphs (with inner connection degree above threshold) + * from a start node in Mode::singleNode + * OR + * in Mode::allNodes : + * complex path lengths (maximal distance in complex path graphs for + * starting nodes u) for all nodes u + * + */ + +class ComplexPathAlgorithm : public Algorithm { +public: + /** + * operation modes + */ + enum Mode { singleNode, allNodes }; + + /** + * Constructs the ComplexPathAlgorithm class for the given Graph @a G. + * depending on the @a mode the algorithm the algorithm + * in @a mode Mode::singleNode starting from @a start + * constructs a subgraph of @a G in which all inner nodes have + * more than @a threshold neighbors + * call getComplexGraph after run to get it + * in @a mode Mode::allNodes constructs these subgraphs for all nodes + * and calculates their longest paths from their start nodes + * these length can be absolute or normalized to [0..1] by calling + * normalize before or after run + * call getPLci after run to get these lengths + * + * @param G The graph. + * @param threshold number of neighbors needed + * @param mode as explained above + * @param start start node for Mode::singleNode + */ + ComplexPathAlgorithm(const Graph &G, count threshold = 3, Mode mode = Mode::allNodes, + node start = none); + + /** + * normalize path lengths + */ + void normalize(); + + void run() override; + + /** + * [normalized] results after running in Mode::allNodes + */ + std::vector getPLci(); + + /** + * resulting graph after running in Mode::singleNode + */ + GraphW getComplexGraph(); + + /** + * nodes in the resulting graph after running in Mode::singleNode + * which are connected to start by at least threshold paths + */ + std::vector getAdopters(); + +private: + const Graph *inputGraph; + GraphW complexPathGraph; + std::vector complexPathsLengths; + std::vector adopters; + const Mode mode; + const node start; + const count threshold; + bool normPaths; + + GraphW complexPathsGraph(node seed, count threshold, std::vector *adopters); + std::vector complexPathLength(count t); + std::vector generateSeeds(node seed, const Graph &g, count threshold); +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_COMPLEX_PATHS_HPP_ diff --git a/vendor/include/networkit/centrality/CoreDecomposition.hpp b/vendor/include/networkit/centrality/CoreDecomposition.hpp new file mode 100644 index 0000000..a917c27 --- /dev/null +++ b/vendor/include/networkit/centrality/CoreDecomposition.hpp @@ -0,0 +1,161 @@ +/* + * CoreDecomposition.hpp + * + * Created on: Oct 28, 2013 + * Author: Lukas Barth, David Weiss, Christian Staudt + */ + +#ifndef NETWORKIT_CENTRALITY_CORE_DECOMPOSITION_HPP_ +#define NETWORKIT_CENTRALITY_CORE_DECOMPOSITION_HPP_ + +#include +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Computes k-core decomposition of a graph. + */ +class CoreDecomposition : public Centrality { + +public: + /** + * Create CoreDecomposition class for graph @a G. The graph may not contain self-loops. + * + * Contains the parallel algorithm by + * Dasari, N.S.; Desh, R.; Zubair, M., "ParK: An efficient algorithm for k-core decomposition on + * multicore processors," in Big Data (Big Data), * 2014 IEEE International Conference. + * + * TODO complexity? + * @param G The graph. + * @param normalized If set to @c true the scores are normalized in the interval [0,1]. + * @param enforceBucketQueueAlgorithm If set to @c true, uses a bucket priority queue data + * structure. This it is generally slower than ParK but may be more flexible. TODO check + * @param storeNodeOrder If set to @c true, the order of the nodes in ascending order of the + * cores is stored and can later be returned using getNodeOrder(). Enforces the sequential + * bucket priority queue algorithm. + * + * The algorithm runs in parallel if the usage of a bucket priority queue is not enforced and + * if the node ids of the input graph are continuous (i.e., numberOfNodes() = + * upperNodeIdBound()). + */ + CoreDecomposition(const Graph &G, bool normalized = false, + bool enforceBucketQueueAlgorithm = false, bool storeNodeOrder = false); + + /** + * Perform k-core decomposition of graph passed in constructor. + */ + void run() override; + + /** + * Get the k-cores as a graph cover object. + * + * @return the k-cores as a Cover + */ + Cover getCover() const; + + /** + * Get the k-shells as a partition object + * + * @return the k-shells as a Partition + */ + Partition getPartition() const; + + /** + * Get maximum core number. + * + * @return The maximum core number + */ + index maxCoreNumber() const; + + /** + * Get the theoretical maximum of centrality score in the given graph. + * + * @return The theoretical maximum centrality score. + */ + double maximum() override; + + /** + * Get the node order. + * + * This is only possible when storeNodeOrder was set. + * + * @return The nodes sorted by increasing core number. + */ + const std::vector &getNodeOrder() const; + +private: + index maxCore; // maximum core number of any node in the graph + + bool enforceBucketQueueAlgorithm; // in case one wants to switch to the alternative algorithm + + bool canRunInParallel; // signifies if a parallel algorithm can be used + + bool storeNodeOrder; // signifies if the node order shall be stored + + std::vector nodeOrder; // Stores the node order, i.e., all nodes sorted by core number + + /** + * Perform k-core decomposition of graph passed in constructor. + * ParK is an algorithm by Naga Shailaja Dasari, Ranjan Desh, and Zubair M. + * See http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7004366 for details. + */ + void runWithParK(); + + /** + * Perform k-core decomposition of graph passed in constructor. + * The algorithm is based on a bucket priority queue data structure. + * It is generally slower than ParK but may be more flexible. + */ + void runWithBucketQueues(); + + /** + * Determines nodes whose remaining degree equals @a level. + * @param[in] level Shell number (= level) currently processed. + * @param[in] degrees Remaining degree for each node. + * @param[inout] curr Nodes to be processed in current level. + */ + void scan(index level, const std::vector °rees, std::vector &curr); + + /** + * Determines in parallel the nodes whose remaining degree equals @a level. + * @param[in] level Shell number (= level) currently processed. + * @param[in] degrees Remaining degree for each node. + * @param[inout] curr Nodes to be processed in current level. + */ + void scanParallel(index level, const std::vector °rees, std::vector &curr, + std::vector &active); + + /** + * Processes nodes (and their neighbors) identified by previous scan. + * @param[in] level Shell number (= level) currently processed. + * @param[inout] degrees Remaining degree for each node. + * @param[in] curr Nodes to be processed in this call. + * @param[inout] next Nodes to be processed next in current level (certain neighbors of nodes in + * curr). + */ + void processSublevel(index level, std::vector °rees, const std::vector &curr, + std::vector &next); + + /** + * Processes in parallel nodes (and their neighbors) identified by previous scan. + * @param[in] level Shell number (= level) currently processed. + * @param[inout] degrees Remaining degree for each node. + * @param[in] curr Nodes to be processed in this call. + * @param[inout] next Nodes to be processed next in current level (certain neighbors of nodes in + * curr). + */ + void processSublevelParallel(index level, std::vector °rees, + const std::vector &curr, std::vector &next, + std::vector &active); +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_CENTRALITY_CORE_DECOMPOSITION_HPP_ diff --git a/vendor/include/networkit/centrality/DegreeCentrality.hpp b/vendor/include/networkit/centrality/DegreeCentrality.hpp new file mode 100644 index 0000000..ac695b8 --- /dev/null +++ b/vendor/include/networkit/centrality/DegreeCentrality.hpp @@ -0,0 +1,55 @@ +/* + * DegreeCentrality.hpp + * + * Created on: 19.02.2014 + * Author: cls + */ + +#ifndef NETWORKIT_CENTRALITY_DEGREE_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_DEGREE_CENTRALITY_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Node centrality index which ranks nodes by their degree. + * Optional normalization by maximum degree. + */ +class DegreeCentrality : public Centrality { +public: + /** + * Constructs the DegreeCentrality class for the given Graph @a G. If the centrality scores + * should be normalized, then set @a normalized to true. run() runs in O(n) time if + * ignoreSelfLoops is false or the graph has no self-loops; otherwise it runs in O(m). + * + * @param G The graph. + * @param normalized Set this parameter to true if scores should be normalized in + * the interval [0,1]. + * @param outDeg If set to true, computes the centrality based on the out-degrees, + * otherwise based on the in-degrees. + * @param ignoreSelfLoops If set to true, self loops will not be taken into + * account. + */ + DegreeCentrality(const Graph &G, bool normalized = false, bool outDeg = true, + bool ignoreSelfLoops = true); + + /** + * Computes degree centraity on the graph passed in constructor. + */ + void run() override; + + /** + * @return the theoretical maximum degree centrality, which is $n$ (including the possibility of + * a self-loop) + */ + double maximum() override; + +private: + bool outDeg, ignoreSelfLoops; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_DEGREE_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/DynApproxBetweenness.hpp b/vendor/include/networkit/centrality/DynApproxBetweenness.hpp new file mode 100644 index 0000000..899025d --- /dev/null +++ b/vendor/include/networkit/centrality/DynApproxBetweenness.hpp @@ -0,0 +1,95 @@ +/* + * DynApproxBetweenness.hpp + * + * Created on: 31.07.2014 + * Author: ebergamini + */ + +#ifndef NETWORKIT_CENTRALITY_DYN_APPROX_BETWEENNESS_HPP_ +#define NETWORKIT_CENTRALITY_DYN_APPROX_BETWEENNESS_HPP_ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Interface for dynamic approximated betweenness centrality algorithm. + */ +class DynApproxBetweenness : public Centrality, public DynAlgorithm { + +public: + /** + * Implementation from the algorithm from "Approximating Betweenness Centrality in Fully-dynamic + * Networks" from Internet Mathematics vol. 5 by Elisabetta Bergamini and Henning Meyerhenke + * approximates the betweenness of all vertices so that the scores are within an additive error + * @a epsilon with probability at least (1- @a delta). The values are normalized by default. + * + * @param G the graph + * @param storePredecessors keep track of the lists of predecessors? + * @param epsilon maximum additive error + * @param delta probability that the values are within the error guarantee + * @param universalConstant the universal constant to be used in + * computing the sample size. It is 0.5 by default. + */ + DynApproxBetweenness(const Graph &G, double epsilon = 0.01, double delta = 0.1, + bool storePredecessors = true, double universalConstant = 0.5); + + /** + * Runs the static approximated betweenness centrality algorithm on the initial graph. + */ + void run() override; + + /** + * Updates the betweenness centralities after an edge insertions on the graph. + * + * @param e The edge insertion or deletion. + */ + void update(GraphEvent e) override; + + /** + * Updates the betweenness centralities after a batch of edge insertions on the graph. + * + * @param batch The batch of edge insertions and/or deletions. + */ + void updateBatch(const std::vector &batch) override; + + /** + * Get number of path samples used for last calculation + */ + count getNumberOfSamples() const noexcept; + +private: + void sampleNewPaths(count start, count end); + double epsilon; //!< maximum error + double delta; + bool storePreds; + const double universalConstant; + count r; + std::vector> sssp; + std::vector> npaths; + + std::vector u; + std::vector v; + std::vector> sampledPaths; + + static constexpr edgeweight infDist = std::numeric_limits::max(); + + std::vector sortComponentsTopologically(GraphW &sccDAG, StronglyConnectedComponents &scc); + + count computeVDdirected(); +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_DYN_APPROX_BETWEENNESS_HPP_ diff --git a/vendor/include/networkit/centrality/DynBetweenness.hpp b/vendor/include/networkit/centrality/DynBetweenness.hpp new file mode 100644 index 0000000..793b27a --- /dev/null +++ b/vendor/include/networkit/centrality/DynBetweenness.hpp @@ -0,0 +1,99 @@ +/* + * DynBetweenness.hpp + * + * Created on: 12.08.2015 + * Author: Arie Slobbe, Elisabetta Bergamini + */ + +#ifndef NETWORKIT_CENTRALITY_DYN_BETWEENNESS_HPP_ +#define NETWORKIT_CENTRALITY_DYN_BETWEENNESS_HPP_ + +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +class CompareDist { +public: + bool operator()(std::pair n1, std::pair n2) { + return n1.first > n2.first; + } +}; + +using PrioQ = + std::priority_queue, std::vector>, CompareDist>; + +/** + * @ingroup centrality + * Dynamic APSP. + */ +class DynBetweenness : public Centrality, public DynAlgorithm { + +public: + /** + * Creates the object for @a G. + * + * @param G The graph. + */ + DynBetweenness(const Graph &G); + + /** + * Runs static betweenness centrality algorithm on the initial graph. + */ + void run() override; + + /** + * Updates the betweenness centralities after an edge insertions on the graph. + * Notice: it works only with edge insertions. + * + * @param e The edge insertions. + */ + void update(GraphEvent e) override; + + /** + * Updates the betweenness centralities after a batch of edge insertions on the graph. + * Notice: it works only with edge insertions. + * + * @param batch The batch of edge insertions. + */ + void updateBatch(const std::vector &batch) override; + + /** Returns number of visited pairs */ + count visPairs(); + + edgeweight getDistance(node u, node v); + edgeweight getSigma(node u, node v); + + count numAffectedAPSP(); + + count numAffectedDep(); + + double getTimeDep(); + +private: + void increaseScore(std::vector &affected, node y, PrioQ &Q); + void decreaseScore(std::vector &affected, node y, PrioQ &Q); + node u; + node v; + edgeweight diameter = 0.0; + const edgeweight infDist = std::numeric_limits::max(); + count visitedPairs = 0; + std::vector> distances; + std::vector> distancesOld; + // total number of shortest paths between two nodes + std::vector> sigma; + std::vector> sigmaOld; + + count affectedAPSP = 0; + count affectedDep = 0; + double timeDep = 0; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_DYN_BETWEENNESS_HPP_ diff --git a/vendor/include/networkit/centrality/DynBetweennessOneNode.hpp b/vendor/include/networkit/centrality/DynBetweennessOneNode.hpp new file mode 100644 index 0000000..cdc631b --- /dev/null +++ b/vendor/include/networkit/centrality/DynBetweennessOneNode.hpp @@ -0,0 +1,98 @@ +/* + * DYNBETNODE.hpp + * + * Created on: 10.03.2016 + * Author: Elisabetta Bergamini + */ + +#ifndef NETWORKIT_CENTRALITY_DYN_BETWEENNESS_ONE_NODE_HPP_ +#define NETWORKIT_CENTRALITY_DYN_BETWEENNESS_ONE_NODE_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup graph + * This algorithm computes the betweenness centrality for a specified focus node x. + * It works for dynamic graphs that can be undirected/directed and unweighted/weighted without + * negative cycles. The Algorithm proceeds as described in [1]. The run() method computes the + * betweenness centrality by computing SSSP (similar to Dijkstra) for each node. + * The update() method only works with edge insertions and edge weight decrements and has a WC + * runtime complexity of O(n²) which outperforms the DynamicBetweenness algorithm for all nodes + * (instead of one focus node) that takes O(nm). + * + * [1] Bergamini et al. : Improving the Betweenness Centrality of a Node by Adding Links + * https://dl.acm.org/doi/abs/10.1145/3166071 + */ + +class DynBetweennessOneNode : public Algorithm, public DynAlgorithm { + +public: + /** + * Creates the object for @a G. + * + * @param G The graph. + * @paarm x The node for which we want to compute betweenness. + */ + DynBetweennessOneNode(Graph &G, node x); + + /** initialize distances and Pred by repeatedly running the Dijkstra2 algorithm */ + void run() override; + + /* Computes the betweenness centrality of x by running BFS for each node */ + void runUnweighted(); + + /* Computes the betweenness centrality of x by running Dijkstra for each node */ + void runWeighted(); + + /** + * Updates the betweenness centrality of x after an edge insertions on the graph. + * Notice: it works only with edge insertions. + * + * @param e The edge insertions. + */ + void update(GraphEvent event) override; + + /** + * Updates the betweenness centrality of x after a batch of edge insertions on the graph. + * Notice: it works only with edge insertions. + * + * @param batch The batch of edge insertions. + */ + void updateBatch(const std::vector &batch) override; + + /** Returns the new betweenness score of node x after the insertion of an edge. Distances and + * scores of the other nodes are not changed by this function. */ + edgeweight computeScore(GraphEvent event); + + edgeweight getDistance(node u, node v); + edgeweight getSigma(node u, node v); + edgeweight getSigmax(node u, node v); + edgeweight getbcx(); + +private: + Graph &G; + node x; + // betweenness centrality of node x + edgeweight bcx = 0; + const edgeweight infDist = std::numeric_limits::max(); + const edgeweight epsilon = + 0.0000000001; // make sure that no legitimate edge weight is below that. + + std::vector> distances; + std::vector> distancesOld; + // total number of shortest paths between two nodes + std::vector> sigma; + // number of shortest paths between two nodes that go through node x + std::vector> sigmax; + std::vector> sigmaxOld; + + std::vector Pred; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_DYN_BETWEENNESS_ONE_NODE_HPP_ diff --git a/vendor/include/networkit/centrality/DynKatzCentrality.hpp b/vendor/include/networkit/centrality/DynKatzCentrality.hpp new file mode 100644 index 0000000..5de7fbe --- /dev/null +++ b/vendor/include/networkit/centrality/DynKatzCentrality.hpp @@ -0,0 +1,115 @@ +/* + * DynKatzCentrality.hpp + * + * Created on: April 2018 + * Author: Alexander van der Grinten + * based on code by Elisabetta Bergamini + */ + +#ifndef NETWORKIT_CENTRALITY_DYN_KATZ_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_DYN_KATZ_CENTRALITY_HPP_ + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Finds the top-k nodes with highest Katz centrality + */ +class DynKatzCentrality : public Centrality, public DynAlgorithm { +protected: + double alpha; // damping + count k; + count maxdeg; + bool groupOnly; + + // Nodes that have Katz score that only differ by this constant might appear + // swapped in the ranking. + double rankTolerance; + +public: + bool useQueue = false; + +public: + /** + * Constructs a DynKatzCentrality object for the given Graph @a G. The damping + * factor is set to 1/(maxdeg + 1), where maxdeg is the maxmum degree in the + * graph. + * + * @param[in] G The graph. + * @param[in] k The number k for which we want to find the top-k nodes with + * highest Katz centrality + * @param[in] groupOnly Set whether the update will only update top-k nodes. + * @param[in] tolerance The tolerance for convergence. + */ + DynKatzCentrality(const Graph &G, count k, bool groupOnly = false, double tolerance = 1e-9); + + void run() override; + + /** + * Updates the katz centralities after an edge insertion or deletion on the + * graph. + * + * @param event The edge insertions or deletion. + */ + void updateBatch(const std::vector &events) override; + + void update(GraphEvent singleEvent) override { + std::vector events{singleEvent}; + updateBatch(events); + } + + node top(count n = 0) { + assert(activeRanking.size() > n); + return activeRanking[n]; + } + + /** + * Returns the (upper) bound of the centrality of each node + */ + double bound(node v); + + /** + * Returns true if the bounds are sharp enough to rank two nodes against each + * other. + */ + bool areDistinguished(node u, node v); + +private: + /** + * Returns true if the bounds are sharp enough to rank two nodes against + * each other **within the tolerance**. + * Precondition: The first node appears higher in the current ranking the the + * second one. + */ + bool areSufficientlyRanked(node high, node low); + + /** + * Performs a single iteration of the algorithm. + */ + void doIteration(); + + /** + * Returns true iff the ranking converged for the top-k. + */ + bool checkConvergence(); + + std::vector isActive; + std::vector activeRanking; + Aux::PrioQueue activeQueue; + bool filledQueue = false; + + std::vector baseData; + std::vector boundData; + +public: // TODO: This is public because tests access it. + std::vector> nPaths; + count levelReached = 0; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_CENTRALITY_DYN_KATZ_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/DynTopHarmonicCloseness.hpp b/vendor/include/networkit/centrality/DynTopHarmonicCloseness.hpp new file mode 100644 index 0000000..484443b --- /dev/null +++ b/vendor/include/networkit/centrality/DynTopHarmonicCloseness.hpp @@ -0,0 +1,223 @@ +/* + * DynTopHarmonicCloseness.hpp + * + * Created on: 28.02.2018 + * Author: nemes, Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_DYN_TOP_HARMONIC_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_DYN_TOP_HARMONIC_CLOSENESS_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace NetworKit { + +/** + * Manages the list of the k nodes with the highest closeness centrality in a + * dynamic graph. + * + * @ingroup centrality + */ +class DynTopHarmonicCloseness : public Algorithm, public DynAlgorithm { +public: + /** + * Constructs the DynTopHarmonicCloseness class. This class implements dynamic + * algorithms for harmonic top-k closeness centrality. The implementation + * is based on the static algorithms by Borassi et al. (complex networks) + * and Bergamini et al. (large-diameter networks). + * + * @param G The graph. + * @param k The number of top nodes. + * @param useBFSbound Whether to use the algorithm for networks with large + * diameter + */ + DynTopHarmonicCloseness(const Graph &G, count k = 1, bool useBFSbound = false); + + ~DynTopHarmonicCloseness() override; + + /** + * Computes the k most central nodes on the initial graph. + */ + void run() override; + + /** + * Returns a list with the k most central nodes. + * WARNING: closeness centrality of some nodes below the top-k could be equal + * to the k-th closeness, we call them trail. Set the parameter includeTrail + * to true to also include those nodes but consider that the resulting vector + * could be longer than k. + * + * @param includeTrail Whether or not to include trail nodes. + * @return The list of the top-k nodes. + */ + std::vector topkNodesList(bool includeTrail = false); + + /** + * Returns a list with the k highest closeness centralities. + * WARNING: closeness centrality of some nodes below the top-k could + * be equal to the k-th closeness, we call them trail. Set the parameter + * includeTrail to true to also include those centrality values but consider + * that the resulting vector could be longer than k. + * + * @param includeTrail Whether or not to include trail centrality value. + * @return The closeness centralities of the k most central nodes. + */ + std::vector topkScoresList(bool includeTrail = false); + + /** + * Returns the ranking of the k most central nodes in the graph. + * WARNING: closeness centrality of some nodes below the top-k could be equal + * to the k-th closeness, we call them trail. Set the parameter includeTrail + * to true to also include those nodes but consider that the resulting vector + * could be longer than k. + * + * @param includeTrail Whether or not to include trail nodes. + * @return The ranking. + */ + std::vector> ranking(bool includeTrail = false); + + void reset(); + + /** + * Updates the list of the k nodes with the highest closeness in G. + * + * @param event The edge modification event. + */ + void update(GraphEvent event) override; + + /** + * Updates the list of k nodes with the highest closeness in G + * after a batch of updates. + * + * @param batch A vector of edge modification events. + */ + void updateBatch(const std::vector &batch) override; + +protected: + /** + * Runs a pruned BFS from the node @a u. The search is aborted once the + * closeness centrality of @a u must be smaller than @a x. + * + * @param v The start node. + * @param x The closeness centrality of the k-th most central node. + * @param n The number of nodes in the graph. + * @param r The number of reachable nodes (or an upper bound in directed + * graphs) for each node. + * @param visited The vector containing the visited status. + * @param distances The vector containing the distances. + * @param pred The vector containing the predecessor of each node. + * @param visitedEdges The number of visited edges. + * @return + */ + std::pair BFScut(node v, edgeweight x, count n, count r, + std::vector &visited, std::vector &distances, + std::vector &pred, count &visitedEdges); + + /** + * Computes the exact closeness centrality of the node @a x and stores upper + * bounds for all other nodes in @a S2. + * + * @param x The start node. + * @param S2 The upper bounds for all other nodes. + * @param visEdges The number of visited edges. + */ + void BFSbound(node x, std::vector &S2, count *visEdges); + + /** + * Handles an edge insertion. + * + * @param event The graph event. + */ + void addEdge(const GraphEvent &event); + + /** + * Handles an edge removal. + * + * @param event The graph event. + */ + void removeEdge(const GraphEvent &event); + + /** + * Computes the number of reachable nodes or an upper bound in directed + * graphs. + */ + void computeReachableNodes(); + /** + * Computes an upper bound for the number of reachable nodes for each node + * in a directed graph. + */ + void computeReachableNodesDirected(); + /** + * Computes the number of reachable nodes in an undirected graph. + */ + void computeReachableNodesUndirected(); + + /** + * Recomputes the number of reachable nodes in an undirected graph after + * inserting an edge between @a u and @a v. + * @param u The first node. + * @param v The second node. + */ + void updateReachableNodesAfterInsertion(node u, node v); + + /** + * Recomputes the number of reachable nodes in an undirected graph after + * removing an edge between @a u and @a v. + * @param u The first node. + * @param v The second node. + */ + void updateReachableNodesAfterDeletion(const GraphEvent &event); + + void init(); + + const Graph &G; + count n; + count k; + bool useBFSbound; + count trail; + double minCloseness; + count nMinCloseness; + std::vector topk; + std::vector topkScores; + std::vector allScores; + std::vector isExact; + std::vector isValid; + std::vector cutOff; + std::vector exactCutOff; + DynConnectedComponents *comps; + bool hasComps = false; + Partition component; + DynWeaklyConnectedComponents *wComps; + bool hasWComps = false; + std::vector r; + std::vector rOld; + std::vector reachL; +}; + +inline std::vector DynTopHarmonicCloseness::topkNodesList(bool includeTrail) { + assureFinished(); + if (!includeTrail) { + auto begin = topk.begin(); + std::vector topkNoTrail(begin, begin + k); + return topkNoTrail; + } + return topk; +} + +inline std::vector DynTopHarmonicCloseness::topkScoresList(bool includeTrail) { + assureFinished(); + if (!includeTrail) { + auto begin = topkScores.begin(); + std::vector topkScoresNoTrail(begin, begin + k); + return topkScoresNoTrail; + } + return topkScores; +} + +} /* namespace NetworKit */ +#endif // NETWORKIT_CENTRALITY_DYN_TOP_HARMONIC_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/centrality/EigenvectorCentrality.hpp b/vendor/include/networkit/centrality/EigenvectorCentrality.hpp new file mode 100644 index 0000000..61e1dda --- /dev/null +++ b/vendor/include/networkit/centrality/EigenvectorCentrality.hpp @@ -0,0 +1,41 @@ +/* + * EigenvectorCentrality.hpp + * + * Created on: 19.03.2014 + * Author: Henning + */ + +#ifndef NETWORKIT_CENTRALITY_EIGENVECTOR_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_EIGENVECTOR_CENTRALITY_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Computes the leading eigenvector of the graph's adjacency matrix (normalized in 2-norm). + * Interpreted as eigenvector centrality score. + */ +class EigenvectorCentrality final : public Centrality { + const double tol; // error tolerance + +public: + /** + * Constructs an EigenvectorCentrality object for the given Graph @a G. @a tol defines the + * tolerance for convergence. + * + * @param[in] G The graph. + * @param[in] tol The tolerance for convergence. + * TODO running time + */ + EigenvectorCentrality(const Graph &G, double tol = 1e-8); + + /** + * Computes eigenvector centrality on the graph passed in constructor. + */ + void run() override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_CENTRALITY_EIGENVECTOR_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/EstimateBetweenness.hpp b/vendor/include/networkit/centrality/EstimateBetweenness.hpp new file mode 100644 index 0000000..d518dcf --- /dev/null +++ b/vendor/include/networkit/centrality/EstimateBetweenness.hpp @@ -0,0 +1,51 @@ +/* + * EstimateBetweenness.hpp + * + * Created on: 13.06.2014 + * Author: Christian Staudt, Elisabetta Bergamini + */ + +#ifndef NETWORKIT_CENTRALITY_ESTIMATE_BETWEENNESS_HPP_ +#define NETWORKIT_CENTRALITY_ESTIMATE_BETWEENNESS_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Estimation of betweenness centrality according to algorithm described in + * Sanders, Geisberger, Schultes: Better Approximation of Betweenness Centrality. + * There is no proven theoretical guarantee on the quality of the approximation. However, the + * algorithm was shown to perform well in practice. If a guarantee is required, use + * ApproxBetweenness. + */ +class EstimateBetweenness : public Centrality { + +public: + /** + * The algorithm estimates the betweenness of all nodes, using weighting + * of the contributions to avoid biased estimation. The run() method takes O(m) + * time per sample, where m is the number of edges of the graph. + * + * @param graph input graph + * @param nSamples user defined number of samples + * @param normalized normalize centrality values in interval [0,1] ? + * @param parallel_flag if true, run in parallel with additional memory cost z + 3z * t + */ + EstimateBetweenness(const Graph &G, count nSamples, bool normalized = false, + bool parallel_flag = false); + + /** + * Computes betweenness estimation on the graph passed in constructor. + */ + void run() override; + +private: + count nSamples; + bool parallel_flag; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_ESTIMATE_BETWEENNESS_HPP_ diff --git a/vendor/include/networkit/centrality/ForestCentrality.hpp b/vendor/include/networkit/centrality/ForestCentrality.hpp new file mode 100644 index 0000000..5b58453 --- /dev/null +++ b/vendor/include/networkit/centrality/ForestCentrality.hpp @@ -0,0 +1,112 @@ +/* + * ForestCentrality.hpp + * + * Created on: 12.02.2020 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_FOREST_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_FOREST_CENTRALITY_HPP_ + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace NetworKit { + +// NOTE: Does not support multiple calls of run() +class ForestCentrality final : public Centrality { + +public: + /** + * Approximates the forest closeness centrality of all the vertices of a graph by approximating + * the diagonal of the forest matrix of @a G. Every element of the diagonal is guaranteed to + * have a maximum absolute error of @a epsilon. Based on "New Approximation Algorithms for + * Forest Closeness Centrality - for Individual Vertices and Vertex Groups", van der Grinten et + * al, SDM 2021. + * The algorithm runs in two steps: (i) solving a linear system and (ii) sampling uniform + * spanning trees (USTs). The parameter @a kappa balances the tolerance of the linear sytem + * solver and the number of USTs to be sampled. A high value of @a kappa raises the tolerance + * (solver converges faster) but more USTs need to be sampled, vice versa for a low value of @a + * kappa. Note: the algorithm requires an augmented graph as input (see the reference paper for + * details). An augmented graphs can be generated with GraphTools::createAugmentedGraph. + * + * @param G The input graph. Must be an augmented graph (an augmented graph can be crated with + * GraphTools::createAugmentedGraph. + * @param root Root node of the augmented graph. + * @param epsilon Maximum absolute error of the elements in the diagonal. + * @param kappa Balances the tolerance of the linear system solver and the number of USTs to be + * sampled. + */ + explicit ForestCentrality(const Graph &G, node root, double epsilon = 0.1, double kappa = 0.3); + + /** + * Run the algorithm. + */ + void run() override; + + /** + * Return an epsilon-approximation of the diagonal of the forest matrix. + * + * @return Approximation of the diagonal of the forest matrix. + */ + const std::vector &getDiagonal() const { + assureFinished(); + return diagonal; + } + + /** + * Return the number of sampled USTs. + * + * @return Number of sampled USTs. + */ + count getNumberOfSamples() const noexcept { return numberOfUSTs; } + +private: + node root; + const double epsilon, kappa, volG; + const count numberOfUSTs; + + // Used to mark the status of each node, one vector per thread + std::vector> statusGlobal; + + // Pointers to the parent of the UST, one vector per thread + std::vector> parentsGlobal; + + // Nodes sorted by decreasing degree + std::vector decDegree; + + // Non-normalized approx effective resistance, one per thread. + std::vector> approxEffResistanceGlobal; + + // Distributions for selecting random neighbors + std::vector> uniformDistr; + + // Solution of the linear system + Vector linearSysSol; + + // Diagonal elements + std::vector diagonal; + + count computeNumberOfUSTs() const { + return count{4} + * static_cast(std::ceil( + std::log(2.0 * static_cast(G.numberOfEdges()) * G.numberOfNodes()) + / (2.0 * epsilon * epsilon))); + } + + void sampleUSTs(); + void solveLinearSystem(); + void computeDiagonal(); + void computeScores(); +}; + +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_FOREST_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/GedWalk.hpp b/vendor/include/networkit/centrality/GedWalk.hpp new file mode 100644 index 0000000..9a76f3c --- /dev/null +++ b/vendor/include/networkit/centrality/GedWalk.hpp @@ -0,0 +1,225 @@ +/* GedWalk.hpp + * + * Created on: 18.6.2018 + * Authors: Eugenio Angriman + * Alexander van der Grinten + */ + +#ifndef NETWORKIT_CENTRALITY_GED_WALK_HPP_ +#define NETWORKIT_CENTRALITY_GED_WALK_HPP_ + +#include +#include +#include + +#include + +namespace NetworKit { + +class GedWalk final : public Algorithm { + + using walks = double; + +public: + enum GreedyStrategy { + LAZY, + STOCHASTIC, + lazy = LAZY, // this + following added for backwards compatibility + stochastic = STOCHASTIC + }; + + enum BoundStrategy { + NO, + SPECTRAL, + GEOMETRIC, + ADAPTIVE_GEOMETRIC, + no = NO, // this + following added for backwards compatibility + spectral = SPECTRAL, + geometric = GEOMETRIC, + adaptiveGeometric = ADAPTIVE_GEOMETRIC + }; + + double stocEpsilon = 0.1; + +private: + const Graph *G; + const count k; + const double epsilon; + double alpha; + const BoundStrategy boundStrategy; + GreedyStrategy greedyStrategy; + double spectralDelta; + double degOutMax; + double degInMax; + std::vector alphas; + + // Size of pathsIn / pathsOut and related vectors. + count allocatedLevels = 15; + + double sigmaMax; + + // Similar to gainScore, gainBound and gainW, but for the entire group. + // These values are always maintained exactly. + double groupScore; // Score of the group. + walks groupW; // Number of walks on the last level. + walks groupBound; // Upper bound on the score of the group. + + walks graphW; + + count nLevels = 2; + std::vector group; + std::vector inGroup; + std::vector isExact; + std::vector nodesToPick; + std::vector> pathsIn, pathsOut; + std::vector> pathsHit, pathsMiss; + + // Unless isExact[x], these values might be upper bounds on the true values. + std::vector gainScore; // Marginal score of the group. + std::vector gainW; // Number of marginal walks on the last level. + std::vector gainBound; // Upper bound on the marginal score. + + struct EvaluationResult { + double score; + walks w; + }; + + tlx::d_ary_addressable_int_heap> scoreQ{gainScore}, + boundQ{gainBound}; + + void init(); + double computeGamma(); + void estimateGains(); + void computeMarginalGain(node z); + void maximizeGain(); + bool separateNodes(); + double computeSigmaMax() const; + void fillPQs(); + void updateAlphas(); + EvaluationResult evaluateGraph(); + EvaluationResult evaluateGroup(); + +public: + /** + * Finds a group of `k` vertices with at least ((1 - 1/e) * opt - epsilon) GedWalk centrality + * score, where opt is the highest possible score. The algorithm is based on the paper "Group + * Centrality Maximization for Large-scale Graphs", Angriman et al., ALENEX20. It implements two + * independent greedy strategies (lazy and stochastic). Furthermore, it allows to compute the + * GedWalk score of a given set of nodes. + * + * @param G A (weakly) connected graph. + * @param k The desired group size. + * @param epsilon Precision of the algorithm. + * @param alpha Exponent to compute the GedWalk score. + * @param bs Bound strategy to compute the GedWalk bounds, default: BoundStrategy::GEOMETRIC. + * @param gs Greedy strategy to be used (lazy or stochastic), default: GreedyStrategy::LAZY. + * @param spectralDelta Delta to be used for the spectral bound. + * + * Note: if the graph is weighted, all weights should be in (0, 1]. + */ + GedWalk(const Graph &G, count k = 1, double initEpsilon = 0.1, double alpha = -1., + BoundStrategy bs = BoundStrategy::GEOMETRIC, GreedyStrategy gs = GreedyStrategy::LAZY, + double spectralDelta = 0.5); + + /** + * Run the algorithm. + */ + void run() override; + + /** + * Return the approximate GedWalk score of the computed group. + * + * @return The approximate score of the computed group. + */ + double getApproximateScore() const { + assureFinished(); + return groupScore; + } + + /** + * Return the GedWalk score of the input group. + * + * @param first/last The range that contains the input group. + * @param scoreEpsilon The precision of the score to be computed. + */ + template + double scoreOfGroup(InputIt first, InputIt last, double scoreEpsilon = .1); + + /** + * Return the computed group. + * + * @return The computed group. + */ + std::vector groupMaxGedWalk() const { + assureFinished(); + return group; + } + + const std::vector &boundOfMarginalGains() const { return gainBound; } +}; + +template +double GedWalk::scoreOfGroup(InputIt first, InputIt last, double scoreEpsilon) { + if (boundStrategy == BoundStrategy::SPECTRAL) { + assert(alpha * static_cast(sigmaMax) < 1.); + } else if (boundStrategy == BoundStrategy::GEOMETRIC) { + assert(alpha * static_cast(degInMax) < 1.); + } else { + assert(boundStrategy == BoundStrategy::ADAPTIVE_GEOMETRIC); + assert(alpha * static_cast(degOutMax + degInMax) < 1.); + } + + std::fill(pathsHit[0].begin(), pathsHit[0].end(), walks{0}); + std::fill(pathsMiss[0].begin(), pathsMiss[0].end(), walks{1}); + std::fill(inGroup.begin(), inGroup.end(), static_cast(0)); + while (first != last) { + const auto u = *first; + inGroup[u] = 1; + pathsHit[0][u] = 1.0; + pathsMiss[0][u] = 0.0; + ++first; + } + + graphW = evaluateGraph().w; + + do { + const auto result = evaluateGroup(); + groupScore = result.score; + groupW = result.w; + if (boundStrategy == BoundStrategy::SPECTRAL) { + const double gamma = + std::sqrt(G->numberOfNodes()) * (sigmaMax / (1 - alpha * sigmaMax)); + groupBound = result.score + alphas[nLevels + 1] * gamma * graphW; + } else if (boundStrategy == BoundStrategy::GEOMETRIC) { + const double gamma = (degInMax / (1 - alpha * degInMax)); + groupBound = result.score + alphas[nLevels + 1] * gamma * graphW; + } else { + assert(boundStrategy == BoundStrategy::ADAPTIVE_GEOMETRIC); + groupBound = result.score + alphas[nLevels + 1] * computeGamma() * result.w; + } + + DEBUG("score is ", groupScore, ", bound is ", groupBound); + if (groupBound < groupScore + scoreEpsilon) + return groupScore; + + DEBUG("increasing path length to ", nLevels + 1); + if (nLevels + 1 >= allocatedLevels) { + DEBUG("allocating ", nLevels + 2, " GedWalk levels"); + while (allocatedLevels < nLevels + 2) { + pathsIn.emplace_back((G->upperNodeIdBound())); + pathsOut.emplace_back((G->upperNodeIdBound())); + pathsHit.emplace_back((G->upperNodeIdBound())); + pathsMiss.emplace_back((G->upperNodeIdBound())); + ++allocatedLevels; + } + + updateAlphas(); + } + + ++nLevels; + graphW = evaluateGraph().w; + } while (true); +} + +} // namespace NetworKit +#endif // NETWORKIT_CENTRALITY_GED_WALK_HPP_ diff --git a/vendor/include/networkit/centrality/GroupCloseness.hpp b/vendor/include/networkit/centrality/GroupCloseness.hpp new file mode 100644 index 0000000..0f3f30e --- /dev/null +++ b/vendor/include/networkit/centrality/GroupCloseness.hpp @@ -0,0 +1,115 @@ +/* + * GroupCloseness.hpp + * + * Created on: 03.10.2016 + * Author: elisabetta bergamini + */ + +#ifndef NETWORKIT_CENTRALITY_GROUP_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_GROUP_CLOSENESS_HPP_ + +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class GroupCloseness final : public Algorithm { +public: + /** + * Finds the group of nodes with highest (group) closeness centrality. + * The algorithm is the one proposed in Bergamini et al., ALENEX 2018 and + * finds a solution that is a (1-1/e)-approximation of the optimum. + * The worst-case running time of this approach is quadratic, but usually + * much faster in practice. + * + * @param G An unweighted graph. + * @param k Size of the group of nodes + * @param H If equal 0, simply runs the algorithm proposed in Bergamini et + * al.. If > 0, interrupts all BFSs after H iterations (suggested for very + * large networks). + * @ + */ + GroupCloseness(const Graph &G, count k = 1, count H = 0); + + /** + * Computes the group with maximum closeness on the graph passed in the + * constructor. + */ + void run() override; + + /** + * Returns group with maximum closeness. + */ + std::vector groupMaxCloseness(); + + /** + * Computes farness (i.e., inverse of the closeness) for a given group + * (stopping after H iterations if H > 0). + */ + double computeFarness(const std::vector &S, + count H = std::numeric_limits::max()) const; + + /** + * Computes the score of a specific group. + */ + double scoreOfGroup(const std::vector &group) const; + +private: + edgeweight computeImprovement(node u, count h); + void updateDistances(node u); + const Graph *G; + count k = 1; + std::vector d; + std::vector> d1Global; + std::vector S; + count H = 0; + + void checkGroup(const std::vector &group) const; +}; + +inline std::vector GroupCloseness::groupMaxCloseness() { + assureFinished(); + return S; +} + +inline void GroupCloseness::checkGroup(const std::vector &group) const { + const count z = G->upperNodeIdBound(); + std::vector check(z, false); +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(group.size()); ++i) { + node u = group[i]; + if (u >= z) { + std::stringstream ss; + ss << "Error: node " << u << " is not in the graph.\n"; + throw std::runtime_error(ss.str()); + } + if (check[u]) { + std::stringstream ss; + ss << "Error: the group contains duplicates of node " << u << ".\n"; + throw std::runtime_error(ss.str()); + } + check[u] = true; + } +} + +inline double GroupCloseness::scoreOfGroup(const std::vector &group) const { + double sumDist = 0.; + if (G->isWeighted()) + Traversal::DijkstraFrom(*G, group.begin(), group.end(), + [&](node, edgeweight dist) { sumDist += dist; }); + else + Traversal::BFSfrom(*G, group.begin(), group.end(), + [&](node, count dist) { sumDist += static_cast(dist); }); + + return sumDist > 0. ? ((double)G->upperNodeIdBound() - (double)group.size()) / sumDist : 0.; +} +} /* namespace NetworKit */ +#endif // NETWORKIT_CENTRALITY_GROUP_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/centrality/GroupClosenessGrowShrink.hpp b/vendor/include/networkit/centrality/GroupClosenessGrowShrink.hpp new file mode 100644 index 0000000..ef8871f --- /dev/null +++ b/vendor/include/networkit/centrality/GroupClosenessGrowShrink.hpp @@ -0,0 +1,78 @@ +/* + * GroupClosenessGrowShrink.hpp + * + * Created on: 19.12.2019 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_GROUP_CLOSENESS_GROW_SHRINK_HPP_ +#define NETWORKIT_CENTRALITY_GROUP_CLOSENESS_GROW_SHRINK_HPP_ + +#include +#include + +#include +#include + +namespace NetworKit { + +// pImpl +namespace GroupClosenessGrowShrinkDetails { +template +class GroupClosenessGrowShrinkImpl; +} // namespace GroupClosenessGrowShrinkDetails + +class GroupClosenessGrowShrink final : public Algorithm { + +public: + GroupClosenessGrowShrink(const Graph &graph, const std::vector &group, + bool extended = false, count insertions = 0, + count maxIterations = 100); + /** + * Finds a group of nodes with high group closeness centrality. This is the Grow-Shrink + * algorithm presented in Angriman et al. "Local Search for Group Closeness Maximization on Big + * Graphs" IEEE BigData 2019. The algorithm takes as input a graph and an arbitrary group of + * nodes, and improves the group closeness of the given group by performing vertex exchanges. + * + * @param G A connected undirected graph. + * @param first Iterator for first node of initial group of nodes. + * @param last Iterator for last node of initial group of nodes. + * @param extended Set this parameter to true for the Extended Grow-Shrink algorithm (i.e., + * vertex exchanges are not restricted to only neighbors of the group). + * @param insertions Number of consecutive node insertions and removal per iteration. Let this + * parameter to zero to use Diameter(G)/sqrt(k) nodes (where k is the size of the group). + * @param maxIterations Maximum number of iterations allowed. + */ + template + GroupClosenessGrowShrink(const Graph &G, Iter first, Iter last, bool extended = false, + count insertions = 0, count maxIterations = 100) + : GroupClosenessGrowShrink(G, std::vector(first, last), extended, insertions, + maxIterations) {} + + ~GroupClosenessGrowShrink() override; + + /** + * Runs the algorithm. + */ + void run() override; + + /** + * Returns the computed group. + */ + std::vector groupMaxCloseness() const; + + /** + * Returns the total number of iterations performed by the algorithm. + */ + count numberOfIterations() const; + +private: + const Graph *G; + std::unique_ptr> + weightedImpl; + std::unique_ptr> + unweightedImpl; +}; +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_GROUP_CLOSENESS_GROW_SHRINK_HPP_ diff --git a/vendor/include/networkit/centrality/GroupClosenessLocalSearch.hpp b/vendor/include/networkit/centrality/GroupClosenessLocalSearch.hpp new file mode 100644 index 0000000..2d27737 --- /dev/null +++ b/vendor/include/networkit/centrality/GroupClosenessLocalSearch.hpp @@ -0,0 +1,77 @@ +#ifndef NETWORKIT_CENTRALITY_GROUP_CLOSENESS_LOCAL_SEARCH_HPP_ +#define NETWORKIT_CENTRALITY_GROUP_CLOSENESS_LOCAL_SEARCH_HPP_ + +#include +#include +#include + +#include +#include + +namespace NetworKit { + +class GroupClosenessLocalSearch final : public Algorithm { +public: + /** + * Local search approximation algorithm for Group Closeness Maximization presented in + * "Group-Harmonic and Group-Closeness Maximization – Approximation and Engineering", Angriman + * et al., ALENEX 2021. The algorithm evaluates all possible swaps between a vertex in the group + * and the vertices outside, and performs a swap iff the decrement in farness is at least $$(1 - + * 1 / (k \\cdot (n - k)))$$, where $$k$$ is the number of vertices in the group. Thus, + * even in a best-case scenario the time complexity of this algorithm is $$O(n \\cdot k)$$. To + * keep the number of swaps low, it is recommended to use this algorithm as a refinement step of + * an already good solution computed by a faster algorithm e.g., greedy (GroupCloseness), or + * GrowShrink (GroupClosenessGrowShrink). In undirected graphs the approximation ratio is 1/5, + * on directed graphs it has not been demonstrated. + * + * @param G A graph. + * @param first, last A range that contains the initial group of nodes. + * @param runGrowShrink Whether or not to run the Grow-Shrink algorithm on the initial group. + * @param maxIterations Maximum number of swaps allowed. Prevents the algorithm from performing + * too many swaps by giving up the approximation guarantee. + */ + template + GroupClosenessLocalSearch(const Graph &G, InputIt first, InputIt last, + bool runGrowShrink = true, + count maxIterations = std::numeric_limits::max()) + : GroupClosenessLocalSearch(G, std::vector(first, last), runGrowShrink, + maxIterations) {} + + GroupClosenessLocalSearch(const Graph &G, const std::vector &group, + bool runGrowShrink = true, + count maxIterations = std::numeric_limits::max()); + + /** + * Runs the algorithm. + */ + void run() override; + + /** + * Returns the computed group. + */ + std::vector groupMaxCloseness() const; + + /** + * Returns the number of iterations performed by the algorithm. + */ + count numberOfIterations() const; + + class GroupClosenessLocalSearchInterface : public Algorithm { + public: + template + GroupClosenessLocalSearchInterface(InputIt first, InputIt last) : group(first, last) {} + + std::unordered_set group; + count nIterations; + }; + +private: + const bool weighted; + // Is always one between GroupClosenessLocalSearchImpl, + // see implementation. + std::unique_ptr impl; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_GROUP_CLOSENESS_LOCAL_SEARCH_HPP_ diff --git a/vendor/include/networkit/centrality/GroupClosenessLocalSwaps.hpp b/vendor/include/networkit/centrality/GroupClosenessLocalSwaps.hpp new file mode 100644 index 0000000..6aac2bb --- /dev/null +++ b/vendor/include/networkit/centrality/GroupClosenessLocalSwaps.hpp @@ -0,0 +1,106 @@ +/* + * GroupClosenessLocalSwaps.hpp + * + * Created on: 19.12.2019 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_GROUP_CLOSENESS_LOCAL_SWAPS_HPP_ +#define NETWORKIT_CENTRALITY_GROUP_CLOSENESS_LOCAL_SWAPS_HPP_ + +#ifdef __AVX2__ +#include +#include +#endif // __AVX2__ + +#include +#include +#include +#include + +#include +#include + +namespace NetworKit { + +class GroupClosenessLocalSwaps final : public Algorithm { + + static constexpr float maxInt16 = static_cast(std::numeric_limits::max()); + // Number of random numbers generated at once + static constexpr count K = 16; + +public: + GroupClosenessLocalSwaps(const Graph &G, const std::vector &group, count maxSwaps = 100); + + /** + * Finds a group of nodes with high group closeness centrality. This is the LS-restrict + * algorithm presented in Angriman et al. "Local Search for Group Closeness Maximization on Big + * Graphs" IEEE BigData 2019. The algorithm takes as input a graph and an arbitrary group of + * nodes, and improves the group closeness of the given group by performing vertex exchanges. + * + * @param G A connected, undirected, and unweighted graph. + * @param first, last A range that contains the initial group of nodes. + * @param maxSwaps Maximum number of vertex exchanges allowed. + */ + template + GroupClosenessLocalSwaps(const Graph &graph, InputIt first, InputIt last, count maxSwaps = 100) + : G(&graph), group(first, last), maxSwaps(maxSwaps) { + + if (G->isDirected()) + throw std::runtime_error("Error, this algorithm does not support directed graphs."); + + if (group.empty()) + throw std::runtime_error("Error, empty group."); + + if (G->isWeighted()) + WARN("This algorithm does not support edge Weights, they will be ignored."); + } + + /** + * Runs the algorithm. + */ + void run() override; + + /** + * Returns the computed group. + */ + std::vector groupMaxCloseness() const; + + /** + * Returns the total number of vertex exchanges performed by the algorithm. + */ + count numberOfSwaps() const; + +private: + const Graph *G; + std::vector group, stack; + std::vector distance, sumOfMins; + std::vector gamma, visited; + std::unordered_map idxMap; + std::vector farness, farnessDecrease; + + count maxSwaps, totalSwaps, stackSize; + + void init(); + void bfsFromGroup(); + bool findAndSwap(); + node estimateHighestDecrease(); + void initRandomVector(); + int64_t computeFarnessDecrease(node u); + void resetGamma(node x, index idx); + +#ifdef __AVX2__ + union RandItem { + uint16_t items[K]; + __m256i vec; + }; + std::vector> randVec; +#else + std::vector randVec; +#endif // __AVX2__ + + std::vector> intDistributions; +}; +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_GROUP_CLOSENESS_LOCAL_SWAPS_HPP_ diff --git a/vendor/include/networkit/centrality/GroupDegree.hpp b/vendor/include/networkit/centrality/GroupDegree.hpp new file mode 100644 index 0000000..6457abc --- /dev/null +++ b/vendor/include/networkit/centrality/GroupDegree.hpp @@ -0,0 +1,155 @@ +/* + * GroupDegree.hpp + * + * Created on: 20.04.2018 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_GROUP_DEGREE_HPP_ +#define NETWORKIT_CENTRALITY_GROUP_DEGREE_HPP_ + +#include +#include + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class GroupDegree : public Algorithm { + +public: + /** + * Finds the group with the highest group degree centrality according to the + * definition proposed in 'The centrality of groups and classes' by Everett et + * al. (The Journal of mathematical sociology, 1999). This is a submodular but + * non monotone function so the algorithm can find a solution that is at least + * 1/2 of the optimum. Worst-case running time is quadratic, but usually + * faster in real-world networks. + * The 'countGroupNodes' option also count the nodes inside the group in the + * score, this make the group degree monotone and submodular and the algorithm + * is guaranteed to return a (1 - 1/e)-approximation of the optimal solution. + * + * @param G A graph. + * @param k Size of the group of nodes + * @param countGroupNodes if nodes inside the group should be counted in the + * centrality score. + */ + GroupDegree(const Graph &G, count k = 1, bool countGroupNodes = true); + + /** + * Computes the group with maximum degree centrality of the graph passed in + * the constructor. + */ + void run() override; + + /** + * Returns the group with maximum degree centrality. + */ + std::vector groupMaxDegree(); + + /** + * Returns the score of the group with maximum degree centrality (i.e. the + * number of nodes outside the group that can be reached in one hop from at + * least one node in the group). + */ + count getScore(); + + /** + * Returns the score of the given group. + */ + count scoreOfGroup(const std::vector &group) const; + +protected: + const Graph &G; + const count k; + const bool countGroupNodes; + count n; + std::vector group; + std::vector gain; + std::vector reachable; + std::vector affected; + std::vector inGroup; + Aux::BucketPQ queue; + count groupScore; + + void init(); + void updateQueue(); + void updateGroup(); + void computeScore(); + void checkGroup(const std::vector &group) const; +}; + +inline std::vector GroupDegree::groupMaxDegree() { + assureFinished(); + return group; +} + +inline count GroupDegree::getScore() { + assureFinished(); + return groupScore; +} + +inline void GroupDegree::computeScore() { + groupScore = std::ranges::count(reachable, true); + + if (!countGroupNodes) { + groupScore -= k; + } +} + +inline void GroupDegree::checkGroup(const std::vector &group) const { + const count z = G.upperNodeIdBound(); + std::vector check(z, false); +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(group.size()); ++i) { + node u = group[i]; + if (u >= z) { + std::stringstream ss; + ss << "Error: node " << u << " is not in the graph.\n"; + throw std::runtime_error(ss.str()); + } + if (check[u]) { + std::stringstream ss; + ss << "Error: the group contains duplicates of node " << u << ".\n"; + throw std::runtime_error(ss.str()); + } + check[u] = true; + } +} + +inline count GroupDegree::scoreOfGroup(const std::vector &group) const { + checkGroup(group); + std::vector touched(n, false); + std::vector inGroup(n, false); + + for (count i = 0; i < group.size(); ++i) { + inGroup[group[i]] = true; + } + + auto processNeighbor = [&](const node u, const node v) { + if (inGroup[u]) { + touched[v] = true; + } + }; + + G.forNodes([&](node v) { + if (!inGroup[v]) { + G.forInNeighborsOf(v, [&](node u) { processNeighbor(u, v); }); + } + }); + count result = std::ranges::count(touched, true); + if (countGroupNodes) { + result += group.size(); + } + + return result; +} + +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_GROUP_DEGREE_HPP_ diff --git a/vendor/include/networkit/centrality/GroupHarmonicCloseness.hpp b/vendor/include/networkit/centrality/GroupHarmonicCloseness.hpp new file mode 100644 index 0000000..59095ca --- /dev/null +++ b/vendor/include/networkit/centrality/GroupHarmonicCloseness.hpp @@ -0,0 +1,83 @@ +/* + * GroupHarmonicCloseness.hpp + * + * Created on: 15.12.2020 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_GROUP_HARMONIC_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_GROUP_HARMONIC_CLOSENESS_HPP_ + +#include +#include + +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class GroupHarmonicCloseness final : public Algorithm { + +public: + /** + * Approximation algorithm for the group-harmonic maximization problem. The computed solutions + * have a guaranteed $\\lambda(1 - \\frac{1}{2e})$ (directed graphs) and + * $\\lambda(1 - \\frac{1}/{e})/2$ (undirected graphs) approximation ratio, + * where $\\lambda$ is the ratio + * between the minimal and the maximal edge weight. The algorithm is the one proposed in + * Angriman et al., ALENEX 2021. The worst-case running time of this approach is quadratic, but + * usually much faster in practice. + * + * @param G The input graph. + * @param k Size of the group of nodes. + */ + GroupHarmonicCloseness(const Graph &G, count k = 1); + + /** + * Runs the algorithm. + */ + void run() override; + + /** + * Returns the computed group. + * + * @return The computed group. + */ + const std::vector &groupMaxHarmonicCloseness() const; + + /** + * Computes the group-harmonic score of the group of nodes in the given range. + * + * @param graph The input Graph. + * @param first,last The range that contains the vertices in the group. + * + * @returns The score of the group of nodes in the given range. + */ + template + static double scoreOfGroup(const Graph &graph, InputIt first, InputIt last); + + class GroupHarmonicClosenessInterface : public Algorithm { + public: + std::vector group; + }; + +private: + const bool weighted; + // Always one between GroupHarmonicClosenessUnweighted and GroupHarmonicClosenessWeighted, see + // implementation. + std::unique_ptr impl; + + static double scoreOfGroup(const Graph &graph, const std::vector &inputGroup); +}; + +template +double GroupHarmonicCloseness::scoreOfGroup(const Graph &graph, InputIt first, InputIt last) { + return scoreOfGroup(graph, {first, last}); +} + +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_GROUP_HARMONIC_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/centrality/HarmonicCloseness.hpp b/vendor/include/networkit/centrality/HarmonicCloseness.hpp new file mode 100644 index 0000000..861b144 --- /dev/null +++ b/vendor/include/networkit/centrality/HarmonicCloseness.hpp @@ -0,0 +1,48 @@ +/* + * HarmonicCloseness.hpp + * + * Created on: 24.02.2018 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_HARMONIC_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_HARMONIC_CLOSENESS_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class HarmonicCloseness : public Centrality { +public: + /** + * Constructs the HarmonicCloseness class for the given Graph @a G. If + * the closeness scores should be normalized, then set @a normalized to + * true. The run() method takes O(nm) time, where n is the number + * of nodes and m is the number of edges of the graph. + * + * @param G The graph. + * @param normalized Set this parameter to false if scores should + * not be normalized into an interval of [0, 1]. Normalization only for + * unweighted graphs. + * + */ + HarmonicCloseness(const Graph &G, bool normalized = true); + + /** + * Computes the harmonic closeness centrality on the graph passed in + * constructor. + */ + void run() override; + + /* + * Returns the maximum possible harmonic closeness centrality that a node can + * have in a star graph with the same amount of nodes. + */ + double maximum() override; +}; +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_HARMONIC_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/centrality/KPathCentrality.hpp b/vendor/include/networkit/centrality/KPathCentrality.hpp new file mode 100644 index 0000000..43fcb71 --- /dev/null +++ b/vendor/include/networkit/centrality/KPathCentrality.hpp @@ -0,0 +1,52 @@ +/* + * KPathCentrality.hpp + * + * Created on: 05.10.2014 + * Author: nemes + */ + +#ifndef NETWORKIT_CENTRALITY_K_PATH_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_K_PATH_CENTRALITY_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class KPathCentrality : public Centrality { +public: + /* + * the maximum length of paths + * default value ln(n+m) + */ + count k; + /* + * value in interval [-0.5, 0.5] + * tradeoff between runtime and precision + * -0.5: maximum precision, maximum runtime + * 0.5: lowest precision, lowest runtime + * default value 0.2 + */ + double alpha; + + /** + * Constructs the K-Path Centrality class for the given Graph @a G. + * + * @param G The graph. + * @param alpha tradeoff between precision and runtime. + * @param k maximum length of paths. + * TODO running times + */ + KPathCentrality(const Graph &G, double alpha = 0.2, count k = 0); + + /** + * Computes k-path centrality on the graph passed in constructor. + */ + void run() override; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_K_PATH_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/KadabraBetweenness.hpp b/vendor/include/networkit/centrality/KadabraBetweenness.hpp new file mode 100644 index 0000000..5efd67e --- /dev/null +++ b/vendor/include/networkit/centrality/KadabraBetweenness.hpp @@ -0,0 +1,242 @@ +/* + * KadabraBetweenness.hpp + * + * Created on: 18.07.2018 + * Authors: Eugenio Angriman + * Alexander van der Grinten + */ + +#ifndef NETWORKIT_CENTRALITY_KADABRA_BETWEENNESS_HPP_ +#define NETWORKIT_CENTRALITY_KADABRA_BETWEENNESS_HPP_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +class StateFrame { +public: + StateFrame(const count size) { apx.assign(size, 0); }; + count nPairs = 0; + count epoch = 0; + std::vector apx; + + void reset(count newEpoch) { + std::ranges::fill(apx, 0); + nPairs = 0; + epoch = newEpoch; + } +}; + +class Status { +public: + Status(count k); + const count k; + std::vector top; + std::vector approxTop; + std::vector finished; + std::vector bet; + std::vector errL; + std::vector errU; +}; + +class SpSampler { +private: + const Graph &G; + const ConnectedComponents &cc; + +public: + SpSampler(const Graph &G, const ConnectedComponents &cc); + void randomPath(StateFrame *curFrame); + StateFrame *frame; + std::mt19937_64 rng; + std::uniform_int_distribution distr; + +private: + std::vector timestamp; + uint8_t globalTS = 1; + static constexpr uint8_t stampMask = 0x7F; + static constexpr uint8_t ballMask = 0x80; + std::vector dist; + std::vector nPaths; + std::vector q; + std::vector> spEdges; + + inline node randomNode() const; + void backtrackPath(node source, node target, node start); + void resetSampler(count endQ); + count getDegree(const Graph &graph, node y, bool useDegreeIn); +}; + +/** + * @ingroup centrality + */ +class KadabraBetweenness : public Algorithm { +public: + // See EUROPAR'19 paper for the selection of these parameters. + unsigned int baseItersPerStep = 1000; + double itersPerStepExp = 1.33; + + /** + * Approximation of the betweenness centrality and computation of the top-k + * nodes with highest betweenness centrality according to the algorithm + * described in Borassi M., and Natale E. (2016): KADABRA is an ADaptive + * Algorithm for Betweenness via Random Approximation. + * Parallel implementation by Van der Grinten A., Angriman E., and + * Meyerhenke H.: Parallel Adaptive Sampling with almost no + * Synchronization, Euro-Par 2019. + * https://link.springer.com/chapter/10.1007/978-3-030-29400-7_31 + * ArXiv pre-print: https://arxiv.org/abs/1903.09422. + * + * If k = 0 the algorithm approximates the betweenness centrality of all + * vertices of the graph so that the scores are within an additive error @a + * err with probability at least (1 - @a delta). Otherwise, the algorithm + * computes the exact ranking of the top-k nodes with highest betweenness + * centrality. The algorithm relies on an adaptive random sampling technique + * of shortest paths and the number of samples in the worst case is w = + * ((log(D - 2) + log(2/delta))/err^2 samples, where D is the diameter of + * the graph. Thus, the worst-case performance is O(w * (|E| + |V|)), but + * performs better in practice. + * + * @param G The graph + * @param err Maximum additive error guaranteed when approximating the + * betweenness centrality of all nodes. + * @param delta probability that the values of the betweenness centrality + * are within the error guarantee. + * @param deterministic If true, the algorithm guarantees that the results of two different + * executions is the same for a fixed random seed, regardless of the number of threads. Note + * that this guarantee leads to increased computational and memory complexity. Default: false. + * @param k the number of top-k nodes to be computed. Set it to zero to + * approximate the betweenness centrality of all the nodes. + * @param unionSample algorithm parameter that is automatically chosen. + * @param startFactor algorithm parameter that is automatically chosen. + */ + KadabraBetweenness(const Graph &G, double err = 0.01, double delta = 0.1, + bool deterministic = false, count k = 0, count unionSample = 0, + count startFactor = 100); + + /** + * Executes the Kadabra algorithm. + */ + void run() override; + + /** + * @return The ranking of the nodes according to their approximated + * betweenness centrality. + */ + std::vector> ranking() const; + + /** + * @return Nodes of the graph sorted by their approximated betweenness + * centrality. + */ + std::vector topkNodesList() const { + assureFinished(); + return topkNodes; + } + + /** + * @return Sorted list of approximated betweenness centrality scores. + */ + std::vector topkScoresList() const { + assureFinished(); + return topkScores; + } + + /** + * @return Approximated betweenness centrality score of all the nodes of the + * graph. + */ + std::vector scores() const { + assureFinished(); + return approxSum; + } + + /** + * @return Total number of samples. + */ + count getNumberOfIterations() const { + assureFinished(); + return nPairs; + } + + /** + * @return Upper bound to the number of samples. + */ + double getOmega() const { + assureFinished(); + return omega; + } + + count maxAllocatedFrames() const { + assureFinished(); + return *std::ranges::max_element(maxFrames); + } + +protected: + const Graph &G; + const double delta, err; + const bool deterministic; + const count k, startFactor; + count unionSample; + count nPairs; + const bool absolute; + double deltaLMinGuess, deltaUMinGuess, omega; + std::atomic epochToRead; + int32_t epochRead; + count seed0, seed1; + std::vector maxFrames; + + std::vector topkNodes; + std::vector topkScores; + std::vector> rankingVector; + std::vector> epochFinished; + std::vector samplerVec; + std::unique_ptr top; + std::unique_ptr cc; + + std::vector approxSum; + std::vector deltaLGuess; + std::vector deltaUGuess; + + std::atomic stop; + + void init(); + void computeDeltaGuess(); + void computeBetErr(Status *status, std::vector &bet, std::vector &errL, + std::vector &errU) const; + bool computeFinished(Status *status) const; + void getStatus(Status *status, bool parallel = false) const; + void computeApproxParallel(const std::vector &firstFrames); + double computeF(double btilde, count iterNum, double deltaL) const; + double computeG(double btilde, count iterNum, double deltaU) const; + void fillResult(); + void checkConvergence(Status &status); + + void fillPQ() { + for (count i = 0; i < G.upperNodeIdBound(); ++i) { + top->insert(i, approxSum[i]); + } + } +}; + +inline std::vector> KadabraBetweenness::ranking() const { + assureFinished(); + std::vector> result(topkNodes.size()); +#pragma omp parallel for + for (omp_index i = 0; i < static_cast(result.size()); ++i) { + result[i] = std::make_pair(topkNodes[i], topkScores[i]); + } + return result; +} +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_KADABRA_BETWEENNESS_HPP_ diff --git a/vendor/include/networkit/centrality/KatzCentrality.hpp b/vendor/include/networkit/centrality/KatzCentrality.hpp new file mode 100644 index 0000000..d66ee46 --- /dev/null +++ b/vendor/include/networkit/centrality/KatzCentrality.hpp @@ -0,0 +1,62 @@ +/* + * KatzCentrality.hpp + * + * Created on: 09.01.2015 + * Author: Henning + */ + +#ifndef NETWORKIT_CENTRALITY_KATZ_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_KATZ_CENTRALITY_HPP_ + +#include + +namespace NetworKit { + +enum EdgeDirection : char { + IN_EDGES = 0, + OUT_EDGES = 1, + InEdges = IN_EDGES, // this + following added for backwards compatibility + OutEdges = OUT_EDGES +}; + +/** + * @ingroup centrality + * Computes the Katz centrality of the graph. + * NOTE: There is an inconsistency in the definition in Newman's book (Ch. 7) regarding + * directed graphs; we follow the verbal description, which requires to sum over the incoming + * edges (as opposed to outgoing ones). + */ +class KatzCentrality : public Centrality { + std::vector values; + +protected: + const double alpha; // damping + const double beta; // constant centrality amount + const double tol; // error tolerance + static double defaultAlpha(const Graph &G); + +public: + /** + * Constructs a KatzCentrality object for the given Graph @a G. @a tol defines the tolerance for + * convergence. Each iteration of the algorithm requires O(m) time. The number of iterations + * depends on how long it takes to reach the convergence. + * + * @param[in] G The graph. + * @param[in] alpha Damping of the matrix vector product result, must be non negative. + * Leave this parameter to 0 to use the default value 1 / (max_degree + 1). + * @param[in] beta Constant value added to the centrality of each vertex + * @param[in] tol The tolerance for convergence. + */ + KatzCentrality(const Graph &G, double alpha = 0, double beta = 0.1, double tol = 1e-8); + + /** + * Computes katz centrality on the graph passed in constructor. + */ + void run() override; + + // Whether to count in-edges or out-edges + EdgeDirection edgeDirection = EdgeDirection::IN_EDGES; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_CENTRALITY_KATZ_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/LaplacianCentrality.hpp b/vendor/include/networkit/centrality/LaplacianCentrality.hpp new file mode 100644 index 0000000..3744a6f --- /dev/null +++ b/vendor/include/networkit/centrality/LaplacianCentrality.hpp @@ -0,0 +1,44 @@ +/* + * LaplacianCentrality.hpp + * + * Created on: 08.03.2018 + * Author: Kolja Esders + */ + +#ifndef NETWORKIT_CENTRALITY_LAPLACIAN_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_LAPLACIAN_CENTRALITY_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Computes the Laplacian centrality of the graph. + * + * The implementation is a simplification of the original algorithm proposed by Qi et al. in + * "Laplacian centrality: A new centrality measure for weighted networks". + * + * See https://dl.acm.org/citation.cfm?id=2181343.2181780 for details. + */ +class LaplacianCentrality : public Centrality { +public: + /** + * Constructs a LaplacianCentrality object for the given Graph @a G. + * + * @param G The graph. + * @param normalized Whether scores should be normalized by the energy of the full graph. + */ + LaplacianCentrality(const Graph &G, bool normalized = false); + + /** + * Computes the Laplacian centrality on the graph passed in the constructor. + * + * See https://dl.acm.org/citation.cfm?id=2181343.2181780 for more details about + * Laplacian centrality. + */ + void run() override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_CENTRALITY_LAPLACIAN_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/LocalClusteringCoefficient.hpp b/vendor/include/networkit/centrality/LocalClusteringCoefficient.hpp new file mode 100644 index 0000000..834fd5e --- /dev/null +++ b/vendor/include/networkit/centrality/LocalClusteringCoefficient.hpp @@ -0,0 +1,60 @@ +/* + * LocalClusteringCoefficient.hpp + * + * Created on: 31.03.2015 + * Author: maxv + */ + +#ifndef NETWORKIT_CENTRALITY_LOCAL_CLUSTERING_COEFFICIENT_HPP_ +#define NETWORKIT_CENTRALITY_LOCAL_CLUSTERING_COEFFICIENT_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class LocalClusteringCoefficient : public Centrality { +public: + /** + * Constructs the LocalClusteringCoefficient class for the given Graph @a G. If the local + * clustering coefficient scores should be normalized, then set @a normalized to + * true. The graph may not contain self-loops. + * + * There are two algorithms available. The trivial (parallel) algorithm needs only a small + * amount of additional memory. The turbo mode adds a (sequential, but fast) pre-processing step + * using ideas from [0]. This reduces the running time significantly for most graphs. However, + * the turbo mode needs O(m) additional memory. In practice this should be a bit less than half + * of the memory that is needed for the graph itself. The turbo mode is particularly effective + * for graphs with nodes of very high degree and a very skewed degree distribution. + * + * [0] Triangle Listing Algorithms: Back from the Diversion + * Mark Ortmann and Ulrik Brandes * 2014 Proceedings of the Sixteenth Workshop on Algorithm + * Engineering and Experiments (ALENEX). 2014, 1-8 + * + * @param G The graph. + * @param turbo If the turbo mode shall be activated. + * TODO running time + */ + LocalClusteringCoefficient(const Graph &G, bool turbo = false); + + /** + * Computes the local clustering coefficient on the graph passed in constructor. + */ + void run() override; + + /** + * Get the theoretical maximum of centrality score in the given graph. + * + * @return The maximum centrality score. + */ + double maximum() override; + +protected: + bool turbo; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_LOCAL_CLUSTERING_COEFFICIENT_HPP_ diff --git a/vendor/include/networkit/centrality/LocalPartitionCoverage.hpp b/vendor/include/networkit/centrality/LocalPartitionCoverage.hpp new file mode 100644 index 0000000..3693f7a --- /dev/null +++ b/vendor/include/networkit/centrality/LocalPartitionCoverage.hpp @@ -0,0 +1,43 @@ +#ifndef NETWORKIT_CENTRALITY_LOCAL_PARTITION_COVERAGE_HPP_ +#define NETWORKIT_CENTRALITY_LOCAL_PARTITION_COVERAGE_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * The local partition coverage is the amount of neighbors of a node u that are in the same + * partition as u. + */ +class LocalPartitionCoverage : public Centrality { +public: + /** + * Construct the local partition coverage instance. The running time of the run() method is + * O(m), where m is the number of edges in the graph. + * + * @param G The graph to use + * @param P The partition for which the coverage shall be calculated. + */ + LocalPartitionCoverage(const Graph &G, const Partition &P); + + /** + * Computes local partition coverage on the graph passed in constructor. + * This method runs in parallel. + */ + void run() override; + + /** + * Get the maximum value (1.0) + * + * @return 1.0 + */ + double maximum() override; + +protected: + const Partition &P; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_LOCAL_PARTITION_COVERAGE_HPP_ diff --git a/vendor/include/networkit/centrality/LocalSquareClusteringCoefficient.hpp b/vendor/include/networkit/centrality/LocalSquareClusteringCoefficient.hpp new file mode 100644 index 0000000..e80523a --- /dev/null +++ b/vendor/include/networkit/centrality/LocalSquareClusteringCoefficient.hpp @@ -0,0 +1,42 @@ +/* + * LocalSquareClusteringCoefficient.hpp + * + * Created on: 07.04.2022 + * Author: tillahoffmann + */ + +#ifndef NETWORKIT_CENTRALITY_LOCAL_SQUARE_CLUSTERING_COEFFICIENT_HPP_ +#define NETWORKIT_CENTRALITY_LOCAL_SQUARE_CLUSTERING_COEFFICIENT_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class LocalSquareClusteringCoefficient : public Centrality { +public: + /** + * Constructs the LocalSquareClusteringCoefficient class for the given Graph @a G. + * + * @param G The graph. + */ + LocalSquareClusteringCoefficient(const Graph &G); + + /** + * Computes the local clustering coefficient on the graph passed in constructor. + */ + void run() override; + + /** + * Get the theoretical maximum of centrality score in the given graph. + * + * @return The maximum centrality score. + */ + double maximum() override; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_LOCAL_SQUARE_CLUSTERING_COEFFICIENT_HPP_ diff --git a/vendor/include/networkit/centrality/PageRank.hpp b/vendor/include/networkit/centrality/PageRank.hpp new file mode 100644 index 0000000..80a8dd5 --- /dev/null +++ b/vendor/include/networkit/centrality/PageRank.hpp @@ -0,0 +1,101 @@ +/* + * PageRank.h + * + * Created on: 19.03.2014 + * Author: Henning + */ + +#ifndef NETWORKIT_CENTRALITY_PAGE_RANK_HPP_ +#define NETWORKIT_CENTRALITY_PAGE_RANK_HPP_ + +#include +#include +#include + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Compute PageRank as node centrality measure. In the default mode this computation is in line + * with the original paper "The PageRank citation ranking: Bringing order to the web." by L. Brin et + * al (1999). In later publications ("PageRank revisited." by M. Brinkmeyer et al. (2005) amongst + * others) sink-node handling was added for directed graphs in order to comply with the theoretical + * assumptions by the underlying Markov chain model. This can be activated by setting the matching + * parameter to true. By default this is disabled, since it is an addition to the original + * definition. + * + * Page-Rank values can also be normalized by post-processed according to "Comparing Apples and + * Oranges: Normalized PageRank for Evolving Graphs" by Berberich et al. (2007). This decouples + * the PageRank values from the size of the input graph. To enable this, set the matching parameter + * to true. Note that sink-node handling is automatically activated if normalization is used. + * + * NOTE: There is an inconsistency in the definition in Newman's book (Ch. 7) regarding + * directed graphs; we follow the verbal description, which requires to sum over the incoming + * edges (as opposed to outgoing ones). + */ +class PageRank final : public Centrality { + +public: + enum Norm { + L1_NORM, + L2_NORM, + L1Norm = L1_NORM, // this + following added for backwards compatibility + L2Norm = L2_NORM + }; + + enum SinkHandling { NO_SINK_HANDLING, DISTRIBUTE_SINKS }; + + /** + * Constructs the PageRank class for the Graph @a G + * + * @param[in] G Graph to be processed. + * @param[in] damp Damping factor of the PageRank algorithm. + * @param[in] tol Error tolerance for PageRank iteration. + * @param[in] distributeSinks Set to distribute PageRank values for sink nodes. (default = + * false) + * @param[in] normalized Set to normalize Page-Rank values in order to decouple it from the + * network size. (default = false) + */ + PageRank(const Graph &G, double damp = 0.85, double tol = 1e-8, bool normalized = false, + SinkHandling distributeSinks = SinkHandling::NO_SINK_HANDLING); + + /** + * Computes page rank on the graph passed in constructor. + */ + void run() override; + + /** + * Returns the maximum PageRank score + */ + double maximum() override; + + /** + * Return the number of iterations performed by the algorithm. + * + * @return Number of iterations performed by the algorithm. + */ + count numberOfIterations() const { + assureFinished(); + return iterations; + } + + // Maximum number of iterations allowed + count maxIterations = std::numeric_limits::max(); + + // Norm used as stopping criterion + Norm norm = Norm::L2_NORM; + +private: + double damp; + double tol; + count iterations; + bool normalized; + SinkHandling distributeSinks; + std::atomic max; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_PAGE_RANK_HPP_ diff --git a/vendor/include/networkit/centrality/PermanenceCentrality.hpp b/vendor/include/networkit/centrality/PermanenceCentrality.hpp new file mode 100644 index 0000000..3723b8c --- /dev/null +++ b/vendor/include/networkit/centrality/PermanenceCentrality.hpp @@ -0,0 +1,48 @@ +#ifndef NETWORKIT_CENTRALITY_PERMANENCE_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_PERMANENCE_CENTRALITY_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * Permanence centrality measures how well a vertex belongs to its community. + */ +class PermanenceCentrality : public Algorithm { +public: + /** + * Constructs the PermanenceCentrality class for the given Graph @a G and Partition @a P. + * + * @param G The input graph. + * @param P Partition for graph G. + */ + PermanenceCentrality(const Graph &G, const Partition &P); + void run() override; + + /** + * Returns the permanence centrality of node @a u. + * + * @param u Node in the input graph. + */ + double getPermanence(node u); + + /** + * Returns the intra-clustering coefficient of node @a u. + * + * @param u Node in the input graph. + */ + double getIntraClustering(node u); + +private: + const Graph &G; + const Partition &P; + std::vector inBegin; + std::vector inEdges; + std::vector marker; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_CENTRALITY_PERMANENCE_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/Sfigality.hpp b/vendor/include/networkit/centrality/Sfigality.hpp new file mode 100644 index 0000000..4f0d15c --- /dev/null +++ b/vendor/include/networkit/centrality/Sfigality.hpp @@ -0,0 +1,45 @@ +/* + * Sfigality.hpp + * + * Created on: 20.01.2016 + * Author:Christian Staudt + */ + +#ifndef NETWORKIT_CENTRALITY_SFIGALITY_HPP_ +#define NETWORKIT_CENTRALITY_SFIGALITY_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * The sfigality of a node is the ratio of neighboring nodes that have + * a higher degree than the node itself. + */ +class Sfigality : public Centrality { +public: + /** + * Constructs the Sfigality class for the given Graph @a G. Sfigality is a new type of + * node centrality measures that is high if neighboring nodes have a higher degree, e.g. in + social networks, if your friends have more friends than you. Formally: + * + * $$\\sigma(u) = \\frac{| \\{ v: \\{u,v\\} \\in E, deg(u) < deg(v) \\} |}{ deg(u) }$$ + * + * @param G The graph. + + */ + Sfigality(const Graph &G); + + void run() override; + + /** + * Returns the node that has the most neighbours with a higher degree than itself (max + * Sfigality). + */ + double maximum() override; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_SFIGALITY_HPP_ diff --git a/vendor/include/networkit/centrality/SpanningEdgeCentrality.hpp b/vendor/include/networkit/centrality/SpanningEdgeCentrality.hpp new file mode 100644 index 0000000..6fe4cc5 --- /dev/null +++ b/vendor/include/networkit/centrality/SpanningEdgeCentrality.hpp @@ -0,0 +1,86 @@ +/* + * SpanningEdgeCentrality.hpp + * + * Created on: 29.07.2015 + * Author: henningm + */ + +#ifndef NETWORKIT_CENTRALITY_SPANNING_EDGE_CENTRALITY_HPP_ +#define NETWORKIT_CENTRALITY_SPANNING_EDGE_CENTRALITY_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * + * SpanningEdgeCentrality edge centrality. + * + */ +class SpanningEdgeCentrality : public Centrality { +protected: + double tol; + Lamg lamg; + uint64_t setupTime; + +public: + /** + * Constructs the SpanningEdgeCentrality class for the given Graph @a G. + * @param G The graph. + * @param tol constant used for the approximation: with probability at least 1-1/n, the + * approximated scores are within a factor 1+tol from the exact scores + */ + SpanningEdgeCentrality(const Graph &G, double tol = 0.1); + + /** + * Destructor. + */ + ~SpanningEdgeCentrality() override = default; + + /** + * Compute spanning edge centrality scores exactly for all edges. This solves a linear system + * for each edge, so the empirical running time is O(m^2), where m is the number of edges in the + * graph. + */ + void run() override; + + /** + * Compute approximation by JL projection. This solves k linear systems, where k is + * log(n)/(tol^2). The empirical running time is O(km), where n is the number of nodes and m is + * the number of edges. + */ + void runApproximation(); + + /** + * Compute approximation by JL projection in parallel. This solves k linear systems in parallel, + * where k is log(n)/(tol^2). + */ + void runParallelApproximation(); + + /** + * This method is deprecated and will not be supported in future releases. + * Use runApproximation() instead. + * @param directory + * @return Elapsed time in milliseconds. + */ + uint64_t TLX_DEPRECATED(runApproximationAndWriteVectors(std::string_view graphPath)); + + /** + * @return The elapsed time to setup the solver in milliseconds. + */ + uint64_t getSetupTime() const; + /** + * Compute value for one edge only. This requires a single linear system, so the empricial + * running time is O(m). + * @param[in] u Endpoint of edge. + * @param[in] v Endpoint of edge. + */ + double runForEdge(node u, node v); +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_CENTRALITY_SPANNING_EDGE_CENTRALITY_HPP_ diff --git a/vendor/include/networkit/centrality/TopCloseness.hpp b/vendor/include/networkit/centrality/TopCloseness.hpp new file mode 100644 index 0000000..84f66f8 --- /dev/null +++ b/vendor/include/networkit/centrality/TopCloseness.hpp @@ -0,0 +1,136 @@ +/* + * TopCloseness.hpp + * + * Created on: 03.10.2014 + * Author: ebergamini, michele borassi + */ + +#ifndef NETWORKIT_CENTRALITY_TOP_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_TOP_CLOSENESS_HPP_ + +#include + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class TopCloseness final : public Algorithm { +public: + /** + * Finds the top k nodes with highest closeness centrality faster than + * computing it for all nodes, based on "Computing Top-k Closeness Centrality + * Faster in Unweighted Graphs", Bergamini et al., ALENEX16. The algorithms is + * based on two independent heuristics, described in the referenced paper. We + * recommend to use first_heu = true and second_heu = false for complex + * networks and first_heu = true and second_heu = true for street networks or + * networks with large diameters. Notice that the worst case running time of + * the algorithm is O(nm), where n is the number of nodes and m is the number + * of edges. However, for most networks the empirical running time is O(m). + * + * @param G An unweighted graph. + * @param k Number of nodes with highest closeness that have to be found. For + * example, if k = 10, the top 10 nodes with highest closeness will be + * computed. + * @param first_heu If true, the neighborhood-based lower bound is computed + * and nodes are sorted according to it. If false, nodes are simply sorted by + * degree. + * @param sec_heu If true, the BFSbound is re-computed at each iteration. If + * false, BFScut is used. + */ + TopCloseness(const Graph &G, count k = 1, bool first_heu = true, bool sec_heu = true); + + /** + * Computes top-k closeness on the graph passed in the constructor. + */ + void run() override; + + /** + * Returns a list with the k nodes with highest closeness. + * WARNING: closeness centrality of some nodes below the top-k could be equal + * to the k-th closeness, we call them trail. Set the parameter includeTrail + * to true to also include those nodes but consider that the resulting vector + * could be longer than k. + * + * @param includeTrail Whether or not to include trail nodes. + */ + std::vector topkNodesList(bool includeTrail = false); + + /** + * Returns a list with the scores of the k nodes with highest closeness + * WARNING: closeness centrality of some nodes below the top-k could be equal + * to the k-th closeness, we call them trail. Set the parameter includeTrail + * to true to also include those centrality values but consider that the + * resulting vector could be longer than k. + * + * @param includeTrail Whether or not to include trail centrality value. + */ + std::vector topkScoresList(bool includeTrail = false); + + /** + * @brief Restricts the top-k closeness computation to a subset of nodes. + * If the given list is empty, all nodes in the graph will be considered. + * Note: Actual existence of included nodes in the graph is not checked. + * + * @param nodeList Subset of nodes. + */ + void restrictTopKComputationToNodes(const std::vector &nodeList) { + nodeListPtr = &nodeList; + }; + +private: + const Graph &G; + count n; + count k; + bool first_heu, sec_heu; + std::vector topk; + const std::vector *nodeListPtr; + count visEdges; + count n_op; + count trail; + double maxFarness = -1.0; + count nMaxFarness; + std::vector> nodesPerLevs, sumLevels; + std::vector topkScores; + std::vector farness; + std::shared_ptr> reachLPtr, reachUPtr; + + std::unique_ptr sccsPtr; + + void init(); + double BFScut(node v, double x, std::vector &visited, std::vector &distances, + std::vector &pred, count &visEdges); + void computelBound1(std::vector &S); + void BFSbound(node x, std::vector &S, count &visEdges, + const std::vector &toAnalyze); + void computeReachable(); +}; + +inline std::vector TopCloseness::topkNodesList(bool includeTrail) { + assureFinished(); + if (!includeTrail) { + auto begin = topk.begin(); + std::vector topkNoTrail(begin, begin + k); + return topkNoTrail; + } + + return topk; +} + +inline std::vector TopCloseness::topkScoresList(bool includeTrail) { + assureFinished(); + if (!includeTrail) { + auto begin = topkScores.begin(); + std::vector topkScoresNoTrail(begin, begin + k); + return topkScoresNoTrail; + } + + return topkScores; +} + +} /* namespace NetworKit */ +#endif // NETWORKIT_CENTRALITY_TOP_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/centrality/TopHarmonicCloseness.hpp b/vendor/include/networkit/centrality/TopHarmonicCloseness.hpp new file mode 100644 index 0000000..20c5dc7 --- /dev/null +++ b/vendor/include/networkit/centrality/TopHarmonicCloseness.hpp @@ -0,0 +1,151 @@ +/* + * TopHarmonicCloseness.hpp + * + * Created on: 25.02.2018 + * Authors: nemes, Eugenio Angriman + */ + +#ifndef NETWORKIT_CENTRALITY_TOP_HARMONIC_CLOSENESS_HPP_ +#define NETWORKIT_CENTRALITY_TOP_HARMONIC_CLOSENESS_HPP_ + +#include + +#include +#include +#include +#include + +#include + +namespace NetworKit { + +/** + * @ingroup centrality + */ +class TopHarmonicCloseness final : public Algorithm { +public: + /** + * Finds the top k nodes with highest harmonic closeness centrality faster + * than computing it for all nodes. The implementation is based on + * "Computing Top-k Centrality Faster in Unweighted Graphs", Bergamini et + * al., ALENEX16. The algorithm also works with weighted graphs but only + * with the NBcut variation. We recommend to use useNBbound = false for + * (weighted) complex networks (or networks with small diameter) and + * useNBbound = true for street networks (or networks with large + * diameters). Notice that the worst case running time of the algorithm is + * O(nm), where n is the number of nodes and m is the number of edges. + * However, for most real-world networks the empirical running time is + * O(m). + * + * @param G The input graph. If useNBbound is set to true, edge weights will be ignored. + * @param k Number of nodes with highest harmonic closeness that have to be found. + * For example, k = 10, the top 10 nodes with highest harmonic closeness will be computed. + * @param useNBbound If true, the NBbound variation will be used, otherwise NBcut. + */ + explicit TopHarmonicCloseness(const Graph &G, count k = 1, bool useNBbound = false); + + ~TopHarmonicCloseness() override; + + /** + * Computes top-k harmonic closeness on the graph passed in the constructor. + */ + void run() override; + + /** + * Returns a list with the k nodes with highest harmonic closeness. + * WARNING: closeness centrality of some nodes below the top-k could be equal + * to the k-th closeness, we call them trail. Set the parameter includeTrail + * to true to also include those nodes but consider that the resulting vector + * could be longer than k. + * + * @param includeTrail Whether or not to include trail nodes. + * @return The list of the top-k nodes. + */ + std::vector topkNodesList(bool includeTrail = false); + + /** + * Returns a list with the scores of the k nodes with highest harmonic + * closeness. + * WARNING: closeness centrality of some nodes below the top-k could + * be equal to the k-th closeness, we call them trail. Set the parameter + * includeTrail to true to also include those centrality values but consider + * that the resulting vector could be longer than k. + * + * @param includeTrail Whether or not to include trail centrality value. + * @return The closeness centralities of the k most central nodes. + */ + std::vector topkScoresList(bool includeTrail = false); + + /** + * @brief Restricts the top-k harmonic closeness computation to a subset of nodes. + * If the given list is empty, all nodes in the graph will be considered. + * Note: Actual existence of included nodes in the graph is not checked. + * + * @param nodeList Subset of nodes. + */ + void restrictTopKComputationToNodes(const std::vector &nodeList) { + nodeListPtr = &nodeList; + }; + +private: + const Graph *G; + const count k; + const bool useNBbound; + + std::vector hCloseness; + std::vector reachableNodes; + std::vector> visitedGlobal; + std::vector tsGlobal; + + std::vector topKNodes; + std::vector topKScores; + const std::vector *nodeListPtr; + + // For NBbound + std::vector reachU, reachL; + std::vector> numberOfNodesAtLevelGlobal; + std::vector> nodesAtCurrentLevelGlobal; + std::vector>> nodesAtLevelGlobal; + std::vector levelImprovement; + std::unique_ptr wccPtr; + void updateTimestamp() { + auto &visited = visitedGlobal[omp_get_thread_num()]; + auto &ts = tsGlobal[omp_get_thread_num()]; + if (ts++ == std::numeric_limits::max()) { + ts = 1; + std::fill(visited.begin(), visited.end(), 0); + } + } + + tlx::d_ary_addressable_int_heap> topKNodesPQ; + tlx::d_ary_addressable_int_heap> prioQ; + std::vector trail; + + // For weighted graphs + std::vector>> + dijkstraHeaps; + std::vector> distanceGlobal; + edgeweight minEdgeWeight; + + omp_lock_t lock; + + void init(); + void runNBcut(); + void runNBbound(); + bool bfscutUnweighted(node source, double kthCloseness); + bool bfscutWeighted(node source, double kthCloseness); + void bfsbound(node source); + void computeReachableNodes(); + void computeReachableNodesBounds(); + void computeNeighborhoodBasedBound(); + void updateTopkPQ(node u); + + double initialBoundNBcutUnweighted(node u) const noexcept; + double initialBoundNBcutWeighted(node u) const noexcept; + + template + std::vector resizedCopy(const std::vector &vec) const noexcept; +}; + +} // namespace NetworKit +#endif // NETWORKIT_CENTRALITY_TOP_HARMONIC_CLOSENESS_HPP_ diff --git a/vendor/include/networkit/clique/MaximalCliques.hpp b/vendor/include/networkit/clique/MaximalCliques.hpp new file mode 100644 index 0000000..4b7965c --- /dev/null +++ b/vendor/include/networkit/clique/MaximalCliques.hpp @@ -0,0 +1,83 @@ +#ifndef NETWORKIT_CLIQUE_MAXIMAL_CLIQUES_HPP_ +#define NETWORKIT_CLIQUE_MAXIMAL_CLIQUES_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +/** + * Algorithm for listing all maximal cliques. + * + * The implementation is based on the "hybrid" algorithm described in + * + * Eppstein, D., & Strash, D. (2011). + * Listing All Maximal Cliques in Large Sparse Real-World Graphs. + * In P. M. Pardalos & S. Rebennack (Eds.), + * Experimental Algorithms (pp. 364 - 375). Springer Berlin Heidelberg. + * Retrieved from http://link.springer.com/chapter/10.1007/978-3-642-20662-7_31 + * + * The running time of this algorithm should be in @f$O(d^2 \cdot n \cdot 3^{d/3})@f$ + * where @f$d@f$ is the degeneracy of the graph, i.e., the maximum core number. + * The running time in practice depends on the structure of the graph. In + * particular for complex networks it is usually quite fast, even graphs with + * millions of edges can usually be processed in less than a minute. + */ +class MaximalCliques final : public Algorithm { + +public: + /** + * Construct the maximal cliques algorithm with the given graph. + * + * If the @a maximumOnly argument is set, the algorithm will only store + * the clique of maximum size. Further, this enables some optimizations + * to skip smaller cliques more efficiently leading to a reduced + * running time. + * + * @param G The graph to list the cliques for. + * @param maximumOnly If only a maximum clique shall be found. + */ + MaximalCliques(const Graph &G, bool maximumOnly = false); + + /** + * Construct the maximal cliques algorithm with the given graph and a callback. + * + * The callback is called once for each found clique with a reference to the clique. + * Note that the reference is to an internal object, the callback should not assume that + * this reference is still valid after it returned. + * + * @param G The graph to list cliques for + * @param callback The callback to call for each clique. + */ + MaximalCliques(const Graph &G, std::function &)> callback); + + /** + * Execute the maximal clique listing algorithm. + */ + void run() override; + + /** + * Return all found cliques unless a callback was given. + * + * This method will throw if a callback was given and thus the cliques were not stored. + * If only the maximum clique was stored, it will return exactly one clique unless the graph + * is empty. + * + * @return a vector of cliques, each being represented as a vector of nodes. + */ + const std::vector> &getCliques() const; + +private: + const Graph *G; + + std::vector> result; + + std::function &)> callback; + bool maximumOnly; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_CLIQUE_MAXIMAL_CLIQUES_HPP_ diff --git a/vendor/include/networkit/coarsening/ClusteringProjector.hpp b/vendor/include/networkit/coarsening/ClusteringProjector.hpp new file mode 100644 index 0000000..df55c46 --- /dev/null +++ b/vendor/include/networkit/coarsening/ClusteringProjector.hpp @@ -0,0 +1,59 @@ +/* + * ClusteringProjector.hpp + * + * Created on: 07.01.2013 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COARSENING_CLUSTERING_PROJECTOR_HPP_ +#define NETWORKIT_COARSENING_CLUSTERING_PROJECTOR_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup coarsening + */ +class ClusteringProjector { + +public: + /** + * Given + * @param[in] Gcoarse + * @param[in] Gfine + * @param[in] fineToCoarse + * @param[in] zetaCoarse a clustering of the coarse graph + * + * , project the clustering back to the fine graph to create a clustering of the fine graph. + * @param[out] a clustering of the fine graph + **/ + virtual Partition projectBack(const Graph &Gcoarse, const Graph &Gfine, + const std::vector &fineToCoarse, + const Partition &zetaCoarse); + + /** + * Project a clustering \zeta^{i} of the coarse graph G^{i} back to + * the finest graph G^{0}, using the hierarchy of fine->coarse maps + */ + virtual Partition projectBackToFinest(const Partition &zetaCoarse, + const std::vector> &maps, + const Graph &Gfinest); + + /** + * Assuming that the coarse graph resulted from contracting and represents a clustering of the + * finest graph + * + * @param[in] Gcoarse coarse graph + * @param[in] Gfinest finest graph + * @param[in] maps hierarchy of maps M^{i->i+1} mapping nodes in finer graph to + * supernodes in coarser graph + */ + virtual Partition + projectCoarseGraphToFinestClustering(const Graph &Gcoarse, const Graph &Gfinest, + const std::vector> &maps); +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COARSENING_CLUSTERING_PROJECTOR_HPP_ diff --git a/vendor/include/networkit/coarsening/CoarsenedGraphView.hpp b/vendor/include/networkit/coarsening/CoarsenedGraphView.hpp new file mode 100644 index 0000000..df35fc5 --- /dev/null +++ b/vendor/include/networkit/coarsening/CoarsenedGraphView.hpp @@ -0,0 +1,165 @@ +/* + * CoarsenedGraphView.hpp + * + * Memory-efficient layered graph view for coarsening operations + */ + +#ifndef NETWORKIT_COARSENING_COARSENED_GRAPH_VIEW_HPP_ +#define NETWORKIT_COARSENING_COARSENED_GRAPH_VIEW_HPP_ + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup coarsening + * Memory-efficient view of a coarsened graph that avoids creating new graph structures. + * This class provides a graph-like interface over the original CSR graph by maintaining + * only the node mapping information, computing edges on-demand. + */ +class CoarsenedGraphView { +public: + /** + * Construct a coarsened graph view from the original graph and partition. + * @param originalGraph The original CSR graph + * @param partition Partition defining how nodes are grouped into supernodes + */ + CoarsenedGraphView(const Graph &originalGraph, const Partition &partition); + + /** + * Construct a coarsened graph view by coarsening an existing coarsened view. + * The resulting view still references the original graph and composes the + * original-node mapping directly. + * @param baseView Existing coarsened view + * @param partition Partition over the base view's supernodes + */ + CoarsenedGraphView(const CoarsenedGraphView &baseView, const Partition &partition); + + /** + * Get the number of nodes (supernodes) in the coarsened view + */ + count numberOfNodes() const { return numSupernodes; } + + /** + * Get the number of edges in the coarsened view + */ + count numberOfEdges() const; + + /** + * Check if a supernode exists + */ + bool hasNode(node supernode) const { return supernode < numSupernodes; } + + /** + * Get the degree of a supernode (number of adjacent supernodes) + */ + count degree(node supernode) const; + + /** + * Get the weighted degree of a supernode + * @param countSelfLoopsTwice If true, count self-loops twice (for undirected graphs) + */ + edgeweight weightedDegree(node supernode, bool countSelfLoopsTwice = false) const; + + /** + * Check if there's an edge between two supernodes + */ + bool hasEdge(node u, node v) const; + + /** + * Get the weight of an edge between two supernodes + */ + edgeweight weight(node u, node v) const; + + /** + * Iterate over neighbors of a supernode + * @param supernode The supernode to iterate neighbors for + * @param handle Function to call for each neighbor: void(node neighbor, edgeweight weight) + */ + template + void forNeighborsOf(node supernode, Lambda handle) const { + if (!hasNode(supernode)) + return; + + auto neighbors = getNeighbors(supernode); + for (const auto &entry : neighbors) { + handle(entry.first, entry.second); + } + } + + /** + * Iterate over all edges in the coarsened view + * @param handle Function to call for each edge: void(node u, node v, edgeweight weight) + */ + template + void forEdges(Lambda handle) const { + for (node u = 0; u < numberOfNodes(); ++u) { + forNeighborsOf(u, [&](node v, edgeweight w) { + if (u <= v) { // Only report each edge once for undirected graphs + handle(u, v, w); + } + }); + } + } + + /** + * Parallel iteration over nodes + */ + template + void parallelForNodes(Lambda handle) const { +#pragma omp parallel for + for (omp_index u = 0; u < static_cast(numberOfNodes()); ++u) { + handle(static_cast(u)); + } + } + + /** + * Get the mapping from original nodes to supernodes + */ + const std::vector &getNodeMapping() const { return nodeMapping; } + + /** + * Get original nodes that belong to a supernode + */ + const std::vector &getOriginalNodes(node supernode) const; + + /** + * Check if the graph is weighted (always true for coarsened views) + */ + bool isWeighted() const { return true; } + + /** + * Check if the graph is directed (always false for current implementation) + */ + bool isDirected() const { return false; } + + /** + * Get upper bound for node IDs + */ + node upperNodeIdBound() const { return numSupernodes; } + +private: + const Graph &originalGraph; + std::vector nodeMapping; // original_node -> supernode + std::vector> supernodeToOriginal; // supernode -> [original_nodes] + count numSupernodes; + + /** + * Get neighbors of a supernode (compute on demand, no caching) + */ + std::vector> getNeighbors(node supernode) const { + return computeNeighbors(supernode); + } + + /** + * Compute neighbors of a supernode + */ + std::vector> computeNeighbors(node supernode) const; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_COARSENING_COARSENED_GRAPH_VIEW_HPP_ diff --git a/vendor/include/networkit/coarsening/GraphCoarsening.hpp b/vendor/include/networkit/coarsening/GraphCoarsening.hpp new file mode 100644 index 0000000..9f2cc6a --- /dev/null +++ b/vendor/include/networkit/coarsening/GraphCoarsening.hpp @@ -0,0 +1,57 @@ +/* + * GraphCoarsening.hpp + * + * Created on: 30.10.2012 + * Author: Christian Staudt (christian.staudt@kit.edu) + */ + +#ifndef NETWORKIT_COARSENING_GRAPH_COARSENING_HPP_ +#define NETWORKIT_COARSENING_GRAPH_COARSENING_HPP_ + +#include +#include + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup coarsening + * Abstract base class for graph coarsening/contraction algorithms. + */ +class GraphCoarsening : public Algorithm { + +public: + GraphCoarsening(const Graph &G); + + ~GraphCoarsening() override = default; + + void run() override = 0; + + const GraphW &getCoarseGraph() const; + + GraphW &getCoarseGraph(); + + /** + * Get mapping from fine to coarse node. + */ + const std::vector &getFineToCoarseNodeMapping() const; + + std::vector &getFineToCoarseNodeMapping(); + + /** + * Get mapping from coarse node to collection of fine nodes. + */ + std::map> getCoarseToFineNodeMapping() const; + +protected: + const Graph *G; + GraphW Gcoarsened; + std::vector nodeMapping; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COARSENING_GRAPH_COARSENING_HPP_ diff --git a/vendor/include/networkit/coarsening/MatchingCoarsening.hpp b/vendor/include/networkit/coarsening/MatchingCoarsening.hpp new file mode 100644 index 0000000..b6b8b86 --- /dev/null +++ b/vendor/include/networkit/coarsening/MatchingCoarsening.hpp @@ -0,0 +1,43 @@ +/* + * MatchingCoarsening.hpp + * + * Created on: 30.10.2012 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COARSENING_MATCHING_COARSENING_HPP_ +#define NETWORKIT_COARSENING_MATCHING_COARSENING_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup coarsening + * Coarsens graph according to a matching. + */ +class MatchingCoarsening final : public GraphCoarsening { + +public: + MatchingCoarsening(const Graph &G, const Matching &M, bool noSelfLoops = false); + + /** + * Contracts graph according to a matching. + * + * @param[in] G fine graph + * @param[in] M matching + * @param[in] noSelfLoops if true, self-loops are not produced + * + * @return coarse graph + */ + void run() override; + +private: + const Matching &M; + bool noSelfLoops; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COARSENING_MATCHING_COARSENING_HPP_ diff --git a/vendor/include/networkit/coarsening/ParallelPartitionCoarsening.hpp b/vendor/include/networkit/coarsening/ParallelPartitionCoarsening.hpp new file mode 100644 index 0000000..81146ac --- /dev/null +++ b/vendor/include/networkit/coarsening/ParallelPartitionCoarsening.hpp @@ -0,0 +1,33 @@ +/* + * ParallelPartitionCoarsening.hpp + * + * Created on: 03.07.2014 + * Author: cls + */ + +#ifndef NETWORKIT_COARSENING_PARALLEL_PARTITION_COARSENING_HPP_ +#define NETWORKIT_COARSENING_PARALLEL_PARTITION_COARSENING_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup coarsening + */ +class ParallelPartitionCoarsening final : public GraphCoarsening { +public: + ParallelPartitionCoarsening(const Graph &G, const Partition &zeta, bool parallel = true); + + void run() override; + +private: + const Partition ζ + bool parallel; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_COARSENING_PARALLEL_PARTITION_COARSENING_HPP_ diff --git a/vendor/include/networkit/coarsening/ParallelPartitionCoarseningView.hpp b/vendor/include/networkit/coarsening/ParallelPartitionCoarseningView.hpp new file mode 100644 index 0000000..5272d69 --- /dev/null +++ b/vendor/include/networkit/coarsening/ParallelPartitionCoarseningView.hpp @@ -0,0 +1,62 @@ +/* + * ParallelPartitionCoarseningView.hpp + * + * Memory-efficient partition coarsening using views + */ + +#ifndef NETWORKIT_COARSENING_PARALLEL_PARTITION_COARSENING_VIEW_HPP_ +#define NETWORKIT_COARSENING_PARALLEL_PARTITION_COARSENING_VIEW_HPP_ + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup coarsening + * Memory-efficient partition coarsening that creates a CoarsenedGraphView + * instead of a new graph structure, significantly reducing memory usage. + */ +class ParallelPartitionCoarseningView { +public: + /** + * Constructor + * @param G The input graph + * @param zeta The partition defining how nodes should be grouped + */ + ParallelPartitionCoarseningView(const Graph &G, const Partition &zeta); + + /** + * Run the coarsening algorithm + */ + void run(); + + /** + * Get the coarsened graph view + * @return Shared pointer to the coarsened graph view + */ + std::shared_ptr getCoarsenedGraphView() const { return coarsenedView; } + + /** + * Get the mapping from fine to coarse nodes + * @return Vector mapping original node IDs to coarsened node IDs + */ + const std::vector &getFineToCoarseNodeMapping() const; + + /** + * Check if the algorithm has been run + */ + bool hasRun() const { return hasRunFlag; } + +private: + const Graph *G; + const Partition ζ + std::shared_ptr coarsenedView; + bool hasRunFlag; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_COARSENING_PARALLEL_PARTITION_COARSENING_VIEW_HPP_ diff --git a/vendor/include/networkit/community/AdjustedRandMeasure.hpp b/vendor/include/networkit/community/AdjustedRandMeasure.hpp new file mode 100644 index 0000000..58a2227 --- /dev/null +++ b/vendor/include/networkit/community/AdjustedRandMeasure.hpp @@ -0,0 +1,31 @@ +#ifndef NETWORKIT_COMMUNITY_ADJUSTED_RAND_MEASURE_HPP_ +#define NETWORKIT_COMMUNITY_ADJUSTED_RAND_MEASURE_HPP_ + +#include + +namespace NetworKit { + +/** + * The adjusted rand dissimilarity measure as proposed by Huber and Arabie in "Comparing partitions" + * (http://link.springer.com/article/10.1007/BF01908075) + */ +class AdjustedRandMeasure final : public DissimilarityMeasure { +public: + /** + * Get the adjust rand dissimilarity. Runs in O(n log(n)). + * + * Note that the dissimilarity can be larger than 1 if the partitions are more different than + * expected in the random model. + * + * @param G The graph on which the partitions shall be compared + * @param zeta The first partiton + * @param eta The second partition + * @return The adjusted rand dissimilarity. + */ + double getDissimilarity(const Graph &G, const NetworKit::Partition &zeta, + const NetworKit::Partition &eta) override; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_ADJUSTED_RAND_MEASURE_HPP_ diff --git a/vendor/include/networkit/community/ClusteringGenerator.hpp b/vendor/include/networkit/community/ClusteringGenerator.hpp new file mode 100644 index 0000000..6bf6694 --- /dev/null +++ b/vendor/include/networkit/community/ClusteringGenerator.hpp @@ -0,0 +1,75 @@ +/* + * ClusteringGenerator.hpp + * + * Created on: 10.12.2012 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_CLUSTERING_GENERATOR_HPP_ +#define NETWORKIT_COMMUNITY_CLUSTERING_GENERATOR_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * Provides several methods for generating special clusterings. + */ +class ClusteringGenerator final { + +public: + /** + * Make a singleton clustering of Graph @a G, i.e. a clustering in which every node + * belongs to its own cluster. + * + * @param G The graph. + * @return A Partition in which every node belongs to its own cluster. + */ + Partition makeSingletonClustering(const Graph &G); + + /** + * Make a 1-clustering of Graph @a G, i.e. a clustering in which all nodes belong to the same + * cluster. + * + * @param G The graph. + * @return A Partition in which all nodes belong to the same cluster. + */ + Partition makeOneClustering(const Graph &G); + + /** + * Make a clustering of Graph @a G with @a k clusters to which the nodes are randomly assigned. + * + * @param G The graph. + * @param k The amount of clusters. + * @return A Partition with @a k clusters and each node randomly assigned to one of them. + */ + Partition makeRandomClustering(const Graph &G, count k); + + /** + * Make a clustering of Graph @a G with @a k clusters. The first n/k nodes are assigned to the + * first cluster, the next n/k nodes to the second cluster and so on. + * + * @param G The graph. + * @param k The amount of clusters. + * @return A Partition with @a k clusters and each node assigned like described above. + */ + Partition makeContinuousBalancedClustering(const Graph &G, count k); + + /** + * Make a clustering of a Graph @a G with @a k clusters. Each node u is assigned to cluster u % + * k. When the number of nodes n is quadratic and k is the square root of n, this clustering is + * complementary to the continuous balanced clustering in the sense that no pair of nodes that + * is in the same cluster in one of the clusterings is in the same cluster in the other + * clustering. + * + * @param G The graph. + * @param k The amount of clusters. + * @return A Partition with @a k clusters and each node assigned as described above. + */ + Partition makeNoncontinuousBalancedClustering(const Graph &G, count k); +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_CLUSTERING_GENERATOR_HPP_ diff --git a/vendor/include/networkit/community/CommunityDetectionAlgorithm.hpp b/vendor/include/networkit/community/CommunityDetectionAlgorithm.hpp new file mode 100644 index 0000000..30afacb --- /dev/null +++ b/vendor/include/networkit/community/CommunityDetectionAlgorithm.hpp @@ -0,0 +1,58 @@ +/* + * CommunityDetectionAlgorithm.hpp + * + * Created on: 30.10.2012 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_COMMUNITY_DETECTION_ALGORITHM_HPP_ +#define NETWORKIT_COMMUNITY_COMMUNITY_DETECTION_ALGORITHM_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * Abstract base class for community detection/graph clustering algorithms. + */ +class CommunityDetectionAlgorithm : public Algorithm { +public: + /** + * A community detection algorithm operates on a graph, so the constructor expects a graph. + * + * @param[in] G input graph + */ + CommunityDetectionAlgorithm(const Graph &G); + + /** + * A community detection algorithm operates on a graph, so the constructor expects a graph. + * + * @param[in] G input graph + * @param[in] baseClustering optional; the algorithm will start from the given clustering. + */ + CommunityDetectionAlgorithm(const Graph &G, Partition baseClustering); + + /** Default destructor */ + ~CommunityDetectionAlgorithm() override = default; + + /** + * Apply algorithm to graph + */ + void run() override = 0; + + /** + * Returns the result of the run method or throws an error, if the algorithm hasn't run yet. + * @return partition of the node set + */ + virtual const Partition &getPartition() const; + +protected: + const Graph *G; + Partition result; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_COMMUNITY_DETECTION_ALGORITHM_HPP_ diff --git a/vendor/include/networkit/community/Conductance.hpp b/vendor/include/networkit/community/Conductance.hpp new file mode 100644 index 0000000..3b1825a --- /dev/null +++ b/vendor/include/networkit/community/Conductance.hpp @@ -0,0 +1,32 @@ +/* + * Conductance.hpp + * + * Created on: 26.02.2014 + * Author: Henning + */ + +#ifndef NETWORKIT_COMMUNITY_CONDUCTANCE_HPP_ +#define NETWORKIT_COMMUNITY_CONDUCTANCE_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * Compute conductance of a 2-partition, i.e. cut size over volume of smaller set (smaller in + * terms of volume). + */ +class Conductance final : public QualityMeasure { +public: + /** + * @return Conductance of 2-partition @a zeta in graph @a G. + * Requires cluster IDs to be either 0 or 1. + */ + double getQuality(const Partition &zeta, const Graph &G) override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_CONDUCTANCE_HPP_ diff --git a/vendor/include/networkit/community/CoverF1Similarity.hpp b/vendor/include/networkit/community/CoverF1Similarity.hpp new file mode 100644 index 0000000..f625043 --- /dev/null +++ b/vendor/include/networkit/community/CoverF1Similarity.hpp @@ -0,0 +1,53 @@ +#ifndef NETWORKIT_COMMUNITY_COVER_F1_SIMILARITY_HPP_ +#define NETWORKIT_COMMUNITY_COVER_F1_SIMILARITY_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * Compare a given cover to a reference cover using the F1 measure. + * This is a typical similarity measure used to compare the found + * overlapping community structure to a ground truth community + * structure. Each cluster is compared to the best-matching reference + * cluster (in terms of highest F1 score). A value of 1 indicates + * perfect agreement while a while of 0 indicates complete + * disagreement. An example where this measure is used is the + * following paper: + * + * Alessandro Epasto, Silvio Lattanzi, and Renato Paes + * Leme. 2017. Ego-Splitting Framework: from Non-Overlapping to + * Overlapping Clusters. In Proceedings of the 23rd ACM SIGKDD + * International Conference on Knowledge Discovery and Data Mining + * (KDD '17). ACM, New York, NY, USA, 145-154. DOI: + * https://doi.org/10.1145/3097983.3098054 + */ +class CoverF1Similarity final : public LocalCoverEvaluation { +public: + /** + * Initialize the cover F1 similarity. + * + * @param G The graph on which the evaluation is performed. + * @param C The cover that shall be evaluated. + * @param reference The reference cover to which @a C shall be compared. + */ + CoverF1Similarity(const Graph &G, const Cover &C, const Cover &reference); + + /** + * Execute the algorithm. The algorithm is not parallel. + */ + void run() override; + + /** + * @return false - smaller is not better, larger values indicate better matching clusters. + */ + bool isSmallBetter() const override { return false; } + +private: + const Cover *reference; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_COVER_F1_SIMILARITY_HPP_ diff --git a/vendor/include/networkit/community/CoverHubDominance.hpp b/vendor/include/networkit/community/CoverHubDominance.hpp new file mode 100644 index 0000000..962158c --- /dev/null +++ b/vendor/include/networkit/community/CoverHubDominance.hpp @@ -0,0 +1,38 @@ +#ifndef NETWORKIT_COMMUNITY_COVER_HUB_DOMINANCE_HPP_ +#define NETWORKIT_COMMUNITY_COVER_HUB_DOMINANCE_HPP_ + +#include + +namespace NetworKit { + +/** + * A quality measure that measures the dominance of hubs in clusters. The hub dominance of a single + * cluster is defined as the maximum cluster-internal degree of a node in that cluster divided by + * the maximum cluster-internal degree, i.e. the number of nodes in the cluster minus one. The + * value for all clusters is defined as the average of all clusters. + * This implementation is a natural generalization of this measure for covers. + * Strictly speaking this is not a quality measure as this is rather dependent on the type of the + * considered graph, for more information see + * Lancichinetti A, Kivel M, Saramki J, Fortunato S (2010) + * Characterizing the Community Structure of Complex Networks + * PLoS ONE 5(8): e11976. doi: 10.1371/journal.pone.0011976 + * http://www.plosone.org/article/info%3Adoi%2F10.1371%2Fjournal.pone.0011976 + */ +class CoverHubDominance final : public LocalCoverEvaluation { +public: + using LocalCoverEvaluation::LocalCoverEvaluation; + + /** + * Execute the algorithm. The algorithm is not parallel. + */ + void run() override; + + /** + * @return false - smaller is not better, larger values indicate better cluster cohesion. + */ + bool isSmallBetter() const override { return false; } +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_COVER_HUB_DOMINANCE_HPP_ diff --git a/vendor/include/networkit/community/Coverage.hpp b/vendor/include/networkit/community/Coverage.hpp new file mode 100644 index 0000000..27616c9 --- /dev/null +++ b/vendor/include/networkit/community/Coverage.hpp @@ -0,0 +1,25 @@ +/* + * Coverage.hpp + * + * Created on: 02.02.2013 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_COVERAGE_HPP_ +#define NETWORKIT_COMMUNITY_COVERAGE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * Coverage is the fraction of intra-cluster edges. + */ +class Coverage final : public QualityMeasure { +public: + double getQuality(const Partition &zeta, const Graph &G) override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_COVERAGE_HPP_ diff --git a/vendor/include/networkit/community/CutClustering.hpp b/vendor/include/networkit/community/CutClustering.hpp new file mode 100644 index 0000000..11ba514 --- /dev/null +++ b/vendor/include/networkit/community/CutClustering.hpp @@ -0,0 +1,62 @@ +#ifndef NETWORKIT_COMMUNITY_CUT_CLUSTERING_HPP_ +#define NETWORKIT_COMMUNITY_CUT_CLUSTERING_HPP_ + +#include + +namespace NetworKit { + +/** + * Cut clustering algorithm as defined in + * Flake, Gary William; Tarjan, Robert E.; Tsioutsiouliklis, Kostas. Graph Clustering and Minimum + * Cut Trees. Internet Mathematics 1 (2003), no. 4, 385--408. + */ +class CutClustering final : public CommunityDetectionAlgorithm { +public: + /** + * Initialize cut clustering algorithm with parameter alpha. + * + * A value of 0 gives a clustering with one cluster with all nodes, + * A value that equals to the largest edge weight gives singleton clusters. + * + * @param alpha The parameter for the cut clustering + */ + CutClustering(const Graph &G, edgeweight alpha); + + /** + * Apply algorithm to graph + * + * Warning: due to numerical errors the resulting clusters might not be correct. + * This implementation uses the Edmonds-Karp algorithm for the cut calculation. + */ + void run() override; + + /** + * Get the complete hierarchy with all possible parameter values. + * + * Each reported parameter value is the lower bound for the range in which the corresponding + * clustering is calculated by the cut clustering algorithm. + * + * Warning: all reported parameter values are slightly too high in order to avoid wrong + * clusterings because of numerical inaccuracies. Furthermore the completeness of the hierarchy + * cannot be guaranteed because of these inaccuracies. This implementation hasn't been optimized + * for performance. + * + * @param G The Graph instance for which the hierarchy shall be calculated + * + * @return The hierarchy as map + */ + static std::map getClusterHierarchy(const Graph &G); + +private: + /** + * Helper function for the recursive clustering hierarchy calculation. + */ + static void clusterHierarchyRecursion(const Graph &G, edgeweight lower, Partition lowerClusters, + edgeweight upper, Partition upperClusters, + std::map &result); + edgeweight alpha; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_CUT_CLUSTERING_HPP_ diff --git a/vendor/include/networkit/community/DissimilarityMeasure.hpp b/vendor/include/networkit/community/DissimilarityMeasure.hpp new file mode 100644 index 0000000..fc8fcdb --- /dev/null +++ b/vendor/include/networkit/community/DissimilarityMeasure.hpp @@ -0,0 +1,31 @@ +/* + * DissimilarityMeasure.hpp + * + * Created on: 19.01.2013 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_DISSIMILARITY_MEASURE_HPP_ +#define NETWORKIT_COMMUNITY_DISSIMILARITY_MEASURE_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * Base class for all clustering dissimilarity measures. + */ +class DissimilarityMeasure { + +public: + virtual double getDissimilarity(const Graph &G, const Partition &first, + const Partition &second) = 0; + + virtual double getDissimilarity(const Graph &G, const Cover &first, const Cover &second); +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_DISSIMILARITY_MEASURE_HPP_ diff --git a/vendor/include/networkit/community/DynamicNMIDistance.hpp b/vendor/include/networkit/community/DynamicNMIDistance.hpp new file mode 100644 index 0000000..10b514a --- /dev/null +++ b/vendor/include/networkit/community/DynamicNMIDistance.hpp @@ -0,0 +1,44 @@ +/* + * DynamicNMIDistance.hpp + * + * Created on: Jun 26, 2013 + * Author: Henning + */ + +#ifndef NETWORKIT_COMMUNITY_DYNAMIC_NMI_DISTANCE_HPP_ +#define NETWORKIT_COMMUNITY_DYNAMIC_NMI_DISTANCE_HPP_ + +#include +#include + +namespace NetworKit { + +using Matrix = std::vector>; + +/** + * @ingroup community + */ +class DynamicNMIDistance final : public DissimilarityMeasure { +public: + /** + * Computes NMI between two clusterings that belong to two different graphs. + * @a newGraph has evolved from oldGraph, which is only given implicitly via + * @a oldClustering. NMI is only applied to nodes that belong to the intersection + * of oldGraph and @a newGraph. Nodes of oldGraph not existing in @newGraph are + * marked by the entry none in @a newClustering. + */ + double getDissimilarity(const Graph &newGraph, const Partition &oldClustering, + const Partition &newClustering) override; + + void combineValues(double H_sum, double MI, double &NMI, double &NMID) const; + void sanityCheck(double &NMI, double &NMID) const; + + double entropy(const Partition &clustering, count n, std::vector probs); + + bool isInBoth(node u, const Partition &oldClustering, const Partition &newClustering); + + Matrix confusionMatrix(const Graph &G, const Partition &zeta, const Partition &eta); +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_DYNAMIC_NMI_DISTANCE_HPP_ diff --git a/vendor/include/networkit/community/EdgeCut.hpp b/vendor/include/networkit/community/EdgeCut.hpp new file mode 100644 index 0000000..8d385c3 --- /dev/null +++ b/vendor/include/networkit/community/EdgeCut.hpp @@ -0,0 +1,24 @@ +/* + * EdgeCut.hpp + * + * Created on: Jun 20, 2013 + * Author: Henning + */ + +#ifndef NETWORKIT_COMMUNITY_EDGE_CUT_HPP_ +#define NETWORKIT_COMMUNITY_EDGE_CUT_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + */ +class EdgeCut final : public QualityMeasure { +public: + double getQuality(const Partition &zeta, const Graph &G) override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_EDGE_CUT_HPP_ diff --git a/vendor/include/networkit/community/GraphClusteringTools.hpp b/vendor/include/networkit/community/GraphClusteringTools.hpp new file mode 100644 index 0000000..9541e2c --- /dev/null +++ b/vendor/include/networkit/community/GraphClusteringTools.hpp @@ -0,0 +1,103 @@ +/* + * GraphClusteringTools.hpp + */ + +#ifndef NETWORKIT_COMMUNITY_GRAPH_CLUSTERING_TOOLS_HPP_ +#define NETWORKIT_COMMUNITY_GRAPH_CLUSTERING_TOOLS_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + */ +namespace GraphClusteringTools { + +/** + * Get the imbalance of clusters in the given partition. + * + * @param zeta Input partition + * @return total imbalance between clusters + */ +float getImbalance(const Partition &zeta); + +/** + * Get the imbalance of clusters in the given partition compared to a given graph. + * + * @param zeta Input partition + * @param graph Input graph + * @return total imbalance between clusters + */ +float getImbalance(const Partition &zeta, const Graph &graph); + +/** + * Get the communication graph for a given graph and its partition. + * A communication graph consists of a number of nodes, which equal + * the number of clusters in the partition. The edges between nodes + * in the communication graph account for the total edge weight for all + * edges between two clusters. For unweighted graphs, the edge weight in + * the communication graph is equal to the number of edges between two + * clusters. + * + * @param graph The input graph + * @param zeta Partition, which contains information about clusters in the graph + * @return communication graph + */ +GraphW communicationGraph(const Graph &graph, Partition &zeta); + +/** + * Get weightedDegree of node u for a cluster (represented by a partition) of index cid. + * + * @param graph The input graph + * @param zeta Partition, which contains information about clusters in the graph + * @param u node + * @param cid index of cluster + * @return weighted degree of node u for cluster index cid + */ +edgeweight weightedDegreeWithCluster(const Graph &graph, const Partition &zeta, node u, index cid); + +/** + * Check whether a partition is a proper clustering for a given graph + * + * @param graph The input graph + * @param zeta Partition, which contains information about clusters in the graph + * @return True if the partition is a proper clustering, False if not + */ +bool isProperClustering(const Graph &G, const Partition &zeta); + +/** + * Check whether a partition is a proper singleton clustering for a given graph + * + * @param graph The input graph + * @param zeta Partition, which contains information about clusters in the graph + * @return True if the partition is a proper singleton clustering, False if not + */ +bool isSingletonClustering(const Graph &G, const Partition &zeta); + +/** + * Check whether a partition is a proper one clustering for a given graph + * + * @param graph The input graph + * @param zeta Partition, which contains information about clusters in the graph + * @return True if the partition is a proper one clustering, False if not + */ +bool isOneClustering(const Graph &G, const Partition &zeta); + +/** + * Check whether two paritions are equal for a given graph + * + * @param graph The input graph + * @param zeta Partition, which contains information about clusters in the graph + * @param eta Partition, which contains information about clusters in the graph + * @return True if both partitions are the same, False if not + */ +bool equalClusterings(const Partition &zeta, const Partition &eta, Graph &G); + +} // namespace GraphClusteringTools + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_GRAPH_CLUSTERING_TOOLS_HPP_ diff --git a/vendor/include/networkit/community/GraphStructuralRandMeasure.hpp b/vendor/include/networkit/community/GraphStructuralRandMeasure.hpp new file mode 100644 index 0000000..745b002 --- /dev/null +++ b/vendor/include/networkit/community/GraphStructuralRandMeasure.hpp @@ -0,0 +1,28 @@ +/* + * GraphStructuralRandMeasure.hpp + * + * Created on: 16.04.2013 + * Author: cls + */ + +#ifndef NETWORKIT_COMMUNITY_GRAPH_STRUCTURAL_RAND_MEASURE_HPP_ +#define NETWORKIT_COMMUNITY_GRAPH_STRUCTURAL_RAND_MEASURE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * The graph-structural Rand measure assigns a similarity value in [0,1] + * to two partitions of a graph, by considering connected pairs of nodes. + */ +class GraphStructuralRandMeasure final : public DissimilarityMeasure { + +public: + double getDissimilarity(const Graph &G, const Partition &first, + const Partition &second) override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_GRAPH_STRUCTURAL_RAND_MEASURE_HPP_ diff --git a/vendor/include/networkit/community/HubDominance.hpp b/vendor/include/networkit/community/HubDominance.hpp new file mode 100644 index 0000000..cd9fe52 --- /dev/null +++ b/vendor/include/networkit/community/HubDominance.hpp @@ -0,0 +1,46 @@ +#ifndef NETWORKIT_COMMUNITY_HUB_DOMINANCE_HPP_ +#define NETWORKIT_COMMUNITY_HUB_DOMINANCE_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * A quality measure that measures the dominance of hubs in clusters. The hub dominance of a single + * cluster is defined as the maximum cluster-internal degree of a node in that cluster divided by + * the maximum cluster-internal degree, i.e. the number of nodes in the cluster minus one. The + * value for all clusters is defined as the average of all clusters. + * Strictly speaking this is not a quality measure as this is rather dependent on the type of the + * considered graph, for more information see + * Lancichinetti A, Kivel M, Saramki J, Fortunato S (2010) + * Characterizing the Community Structure of Complex Networks + * PLoS ONE 5(8): e11976. doi: 10.1371/journal.pone.0011976 + * http://www.plosone.org/article/info%3Adoi%2F10.1371%2Fjournal.pone.0011976 + */ +class HubDominance final : public QualityMeasure { +public: + /** + * Calculates the dominance of hubs in the given Partition @a zeta of the given + * Graph @a G. + * + * @param zeta The partition for which the hub dominance shall be calculated + * @param G The graph that is partitioned in @a zeta + * @return The average hub dominance of @a zeta + */ + double getQuality(const Partition &zeta, const Graph &G) override; + /** + * Calculates the dominance of hubs in the given Cover @a zeta of the given + * Graph @a G. + * + * @param zeta The cover for which the hub dominance shall be calculated + * @param G The graph that is partitioned in @a zeta + * @return The average hub dominance of @a zeta + */ + double getQuality(const Cover &zeta, const Graph &G); +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_HUB_DOMINANCE_HPP_ diff --git a/vendor/include/networkit/community/IntrapartitionDensity.hpp b/vendor/include/networkit/community/IntrapartitionDensity.hpp new file mode 100644 index 0000000..d169bfc --- /dev/null +++ b/vendor/include/networkit/community/IntrapartitionDensity.hpp @@ -0,0 +1,44 @@ +#ifndef NETWORKIT_COMMUNITY_INTRAPARTITION_DENSITY_HPP_ +#define NETWORKIT_COMMUNITY_INTRAPARTITION_DENSITY_HPP_ + +#include + +namespace NetworKit { + +/** + * The intra-cluster density of a partition is defined as the number of existing edges divided by + * the number of possible edges. The global value is the sum of all existing intra-cluster edges + * divided by the sum of all possible intra-cluster edges. + */ +class IntrapartitionDensity final : public LocalPartitionEvaluation { +public: + using LocalPartitionEvaluation::LocalPartitionEvaluation; + + /** + * Execute the algorithm. The algorithm is not parallel. + */ + void run() override; + + /** + * Get the global intra-cluster density. + * + * @return The global intra-cluster density. + */ + double getGlobal() const { + assureFinished(); + return globalValue; + }; + + /** + * This value should be high in a good clustering. + * @return false - high values are better than small values. + */ + bool isSmallBetter() const override { return false; } + +private: + double globalValue; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_INTRAPARTITION_DENSITY_HPP_ diff --git a/vendor/include/networkit/community/IsolatedInterpartitionConductance.hpp b/vendor/include/networkit/community/IsolatedInterpartitionConductance.hpp new file mode 100644 index 0000000..1a312d4 --- /dev/null +++ b/vendor/include/networkit/community/IsolatedInterpartitionConductance.hpp @@ -0,0 +1,40 @@ +#ifndef NETWORKIT_COMMUNITY_ISOLATED_INTERPARTITION_CONDUCTANCE_HPP_ +#define NETWORKIT_COMMUNITY_ISOLATED_INTERPARTITION_CONDUCTANCE_HPP_ + +#include + +namespace NetworKit { + +/** + * Isolated inter-partition conductance is a measure for how well a partition + * (communtiy/cluster) is separated from the rest of the graph. + * + * The conductance of a partition is defined as the weight of the cut divided + * by the volume (the sum of the degrees) of the nodes in the partition or the + * nodes in the rest of the graph, whatever is smaller. Small values thus indicate + * that the cut is small compared to the volume of the smaller of the separated + * parts. For the whole partitions usually the maximum or the unweighted average + * is used. + * + * See also Experiments on Density-Constrained Graph Clustering, + * Robert Gorke, Andrea Kappes and Dorothea Wagner, JEA 2015: + * http://dx.doi.org/10.1145/2638551 + */ +class IsolatedInterpartitionConductance final : public LocalPartitionEvaluation { +public: + using LocalPartitionEvaluation::LocalPartitionEvaluation; + + /** + * Execute the algorithm. The algorithm is not parallel. + */ + void run() override; + + /** + * @return true - smaller values are better than larger values. + */ + bool isSmallBetter() const override { return true; }; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_ISOLATED_INTERPARTITION_CONDUCTANCE_HPP_ diff --git a/vendor/include/networkit/community/IsolatedInterpartitionExpansion.hpp b/vendor/include/networkit/community/IsolatedInterpartitionExpansion.hpp new file mode 100644 index 0000000..97eb406 --- /dev/null +++ b/vendor/include/networkit/community/IsolatedInterpartitionExpansion.hpp @@ -0,0 +1,40 @@ +#ifndef NETWORKIT_COMMUNITY_ISOLATED_INTERPARTITION_EXPANSION_HPP_ +#define NETWORKIT_COMMUNITY_ISOLATED_INTERPARTITION_EXPANSION_HPP_ + +#include + +namespace NetworKit { + +/** + * Isolated inter-partition expansion is a measure for how well a partition + * (communtiy/cluster) is separated from the rest of the graph. + * + * The expansion of a partition is defined as the weight of the cut divided + * by number of nodes in the partition or in the rest of the graph, whatever + * is smaller. Small values thus indicate that the cut is small compared to + * the size of the smaller of the separated parts. For the whole partitions + * usually the maximum or the unweighted average is used. Note that expansion + * values can be larger than 1. + * + * See also Experiments on Density-Constrained Graph Clustering, + * Robert Grke, Andrea Kappes and Dorothea Wagner, JEA 2015: + * http://dx.doi.org/10.1145/2638551 + */ +class IsolatedInterpartitionExpansion final : public LocalPartitionEvaluation { +public: + using LocalPartitionEvaluation::LocalPartitionEvaluation; + + /** + * Execute the algorithm. The algorithm is not parallel. + */ + void run() override; + + /** + * @return true - smaller values are better than larger values. + */ + bool isSmallBetter() const override { return true; }; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_ISOLATED_INTERPARTITION_EXPANSION_HPP_ diff --git a/vendor/include/networkit/community/JaccardMeasure.hpp b/vendor/include/networkit/community/JaccardMeasure.hpp new file mode 100644 index 0000000..d6b44e0 --- /dev/null +++ b/vendor/include/networkit/community/JaccardMeasure.hpp @@ -0,0 +1,25 @@ +/* + * JaccardMeasure.hpp + * + * Created on: 19.01.2013 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_JACCARD_MEASURE_HPP_ +#define NETWORKIT_COMMUNITY_JACCARD_MEASURE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + */ +class JaccardMeasure final : public DissimilarityMeasure { + +public: + double getDissimilarity(const Graph &G, const Partition &zeta, const Partition &eta) override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_JACCARD_MEASURE_HPP_ diff --git a/vendor/include/networkit/community/LFM.hpp b/vendor/include/networkit/community/LFM.hpp new file mode 100644 index 0000000..d476296 --- /dev/null +++ b/vendor/include/networkit/community/LFM.hpp @@ -0,0 +1,49 @@ +/* + * LFM.hpp + * + * Created on 10.12.2020 + * Author: John Gelhausen + */ + +#ifndef NETWORKIT_COMMUNITY_LFM_HPP_ +#define NETWORKIT_COMMUNITY_LFM_HPP_ + +#include +#include + +namespace NetworKit { +/** + * @ingroup community + * This is the local community expansion algorithm as introduced in: + * + * Lancichinetti, A., Fortunato, S., & Kertész, J. (2009). + * Detecting the overlapping and hierarchical community structure in complex networks. + * New Journal of Physics, 11(3), 033015. + * https://doi.org/10.1088/1367-2630/11/3/033015 + * + * The LFM algorithm detects overlapping communities by repeatedly + * executing a given SelectiveCommunityDetector algorithm + * for different random seed nodes which have not yet been assigned to any community. + * While this implementation allows the use of any local community detection algorithm, the behavior + * of the original algorithm can be achieved using the LFMLocal local community detection algorithm. + */ +class LFM final : public OverlappingCommunityDetectionAlgorithm { +public: + /** + * @param G Input graph + * @param scd The algorithm that is used to expand the random seed nodes to communities + * + */ + LFM(const Graph &G, SelectiveCommunityDetector &scd); + + /** + * Detect communities + */ + void run() override; + +protected: + SelectiveCommunityDetector *scd; +}; +} /* namespace NetworKit */ + +#endif // NETWORKIT_COMMUNITY_LFM_HPP_ diff --git a/vendor/include/networkit/community/LPDegreeOrdered.hpp b/vendor/include/networkit/community/LPDegreeOrdered.hpp new file mode 100644 index 0000000..a7aba92 --- /dev/null +++ b/vendor/include/networkit/community/LPDegreeOrdered.hpp @@ -0,0 +1,48 @@ +/* + * LPDegreeOrdered.hpp + * + * Created on: 24.09.2013 + * Author: cls + */ + +#ifndef NETWORKIT_COMMUNITY_LP_DEGREE_ORDERED_HPP_ +#define NETWORKIT_COMMUNITY_LP_DEGREE_ORDERED_HPP_ + +#include + +namespace NetworKit { + +using label = index; // a label is the same as a cluster id + +/** + * @ingroup community + * Label propagation-based community detection algorithm which + * processes nodes in increasing order of node degree. + */ +class LPDegreeOrdered final : public CommunityDetectionAlgorithm { +private: + count nIterations = 0; //!< number of iterations in last run + +public: + /** + * Constructor to the degree ordered label propagation community detection algorithm. + * + * @param[in] G input graph + */ + LPDegreeOrdered(const Graph &G); + + /** + * Detect communities. + */ + void run() override; + + /** + * Get number of iterations in last run. + * + * @return Number of iterations. + */ + count numberOfIterations(); +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_LP_DEGREE_ORDERED_HPP_ diff --git a/vendor/include/networkit/community/LocalCommunityEvaluation.hpp b/vendor/include/networkit/community/LocalCommunityEvaluation.hpp new file mode 100644 index 0000000..d7fd338 --- /dev/null +++ b/vendor/include/networkit/community/LocalCommunityEvaluation.hpp @@ -0,0 +1,100 @@ +#ifndef NETWORKIT_COMMUNITY_LOCAL_COMMUNITY_EVALUATION_HPP_ +#define NETWORKIT_COMMUNITY_LOCAL_COMMUNITY_EVALUATION_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +/** + * Virtual base class of all evaluation methods for a single clustering which is based on the + * evaluation of single clusters. This is the base class both for Partitions as well as for Covers. + */ +class LocalCommunityEvaluation : public Algorithm { +public: + /** + * Default destructor for the virtual base class + */ + ~LocalCommunityEvaluation() override = default; + + /** + * Get the average value weighted by cluster size. + * + * @return The weighted average value. + */ + double getWeightedAverage() const { + assureFinished(); + return weightedAverage; + }; + + /** + * Get the (unweighted) average value of all clusters. + * + * @return The unweighted average value. + */ + double getUnweightedAverage() const { + assureFinished(); + return unweightedAverage; + }; + + /** + * Get the maximum value of all clusters. + * + * @return The maximum value. + */ + double getMaximumValue() const { + assureFinished(); + return maximumValue; + }; + + /** + * Get the minimum value of all clusters. + * + * @return The minimum value. + */ + double getMinimumValue() const { + assureFinished(); + return minimumValue; + }; + + /** + * Get the value of the specified cluster. + * + * @param i The cluster to get the value for. + * @return The value of cluster @a i. + */ + double getValue(index i) const { + assureFinished(); + return values[i]; + }; + + /** + * Get the values of all clusters. + * + * @return The values of all clusters. + */ + std::vector getValues() const { + assureFinished(); + return values; + }; + + /** + * If small values are better (otherwise large values are better). + * + * @return If small values are better. + */ + virtual bool isSmallBetter() const = 0; + +protected: + double weightedAverage; + double unweightedAverage; + double maximumValue; + double minimumValue; + std::vector values; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_LOCAL_COMMUNITY_EVALUATION_HPP_ diff --git a/vendor/include/networkit/community/LocalCoverEvaluation.hpp b/vendor/include/networkit/community/LocalCoverEvaluation.hpp new file mode 100644 index 0000000..ca15847 --- /dev/null +++ b/vendor/include/networkit/community/LocalCoverEvaluation.hpp @@ -0,0 +1,31 @@ +#ifndef NETWORKIT_COMMUNITY_LOCAL_COVER_EVALUATION_HPP_ +#define NETWORKIT_COMMUNITY_LOCAL_COVER_EVALUATION_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * Virtual base class of all evaluation methods for a single Cover which is based on the evaluation + * of single clusters. This is the base class for Covers. + */ +class LocalCoverEvaluation : public LocalCommunityEvaluation { +public: + /** + * Initialize the cover evaluation method. + * + * @param G The graph on which the evaluation shall be performed + * @param C The cover that shall be evaluated. + */ + LocalCoverEvaluation(const Graph &G, const Cover &C); + +protected: + const Graph *G; + const Cover *C; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_LOCAL_COVER_EVALUATION_HPP_ diff --git a/vendor/include/networkit/community/LocalPartitionEvaluation.hpp b/vendor/include/networkit/community/LocalPartitionEvaluation.hpp new file mode 100644 index 0000000..d7dd825 --- /dev/null +++ b/vendor/include/networkit/community/LocalPartitionEvaluation.hpp @@ -0,0 +1,31 @@ +#ifndef NETWORKIT_COMMUNITY_LOCAL_PARTITION_EVALUATION_HPP_ +#define NETWORKIT_COMMUNITY_LOCAL_PARTITION_EVALUATION_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * Virtual base class of all evaluation methods for a single Partition which is based on the + * evaluation of single clusters. This is the base class for Partitions. + */ +class LocalPartitionEvaluation : public LocalCommunityEvaluation { +public: + /** + * Initialize the partition evaluation method. + * + * @param G The graph on which the evaluation shall be performed + * @param P The partition that shall be evaluated. + */ + LocalPartitionEvaluation(const Graph &G, const Partition &P); + +protected: + const Graph *G; + const Partition *P; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_LOCAL_PARTITION_EVALUATION_HPP_ diff --git a/vendor/include/networkit/community/LouvainMapEquation.hpp b/vendor/include/networkit/community/LouvainMapEquation.hpp new file mode 100644 index 0000000..0bd4aab --- /dev/null +++ b/vendor/include/networkit/community/LouvainMapEquation.hpp @@ -0,0 +1,135 @@ +/* + * LouvainMapEquation.hpp + * + * Created on: 2019-01-28 + * Author: Armin Wiebigke + * Michael Hamann + * Lars Gottesbüren + */ + +#ifndef NETWORKIT_COMMUNITY_LOUVAIN_MAP_EQUATION_HPP_ +#define NETWORKIT_COMMUNITY_LOUVAIN_MAP_EQUATION_HPP_ + +#include +#include +#include + +namespace NetworKit { + +class LouvainMapEquation : public CommunityDetectionAlgorithm { +public: + enum class ParallelizationType : uint8_t { + NONE, + RELAX_MAP, + SYNCHRONOUS, + None = NONE, // this + following added for backwards compatibility + RelaxMap = RELAX_MAP, + Synchronous = SYNCHRONOUS + }; + +public: + /** + * @param[in] G input graph + * @param[in] hierarchical use recursive coarsening + * @param[in] maxIterations maximum number of iterations for move phase + * @param[in] parallelization strategy (default synchronous): + * none + * relaxmap -> one lock per community to update cuts + * synchronous -> work on stale cuts and volumes, update in second step + * + */ + explicit LouvainMapEquation(const Graph &graph, bool hierarchical = false, + count maxIterations = 32, + std::string_view parallelizationStrategy = "relaxmap"); + /** + * @param[in] G input graph + * @param[in] hierarchical use recursive coarsening + * @param[in] maxIterations maximum number of iterations for move phase + * @param[in] parallelization strategy (default synchronous): + * none + * relaxmap -> one lock per community to update cuts + * synchronous -> work on stale cuts and volumes, update in second step + * + */ + explicit LouvainMapEquation(const Graph &graph, bool hierarchical, count maxIterations, + ParallelizationType parallelizationType); + + void run() override; + +private: + struct Move { + node movedNode = none; + double volume = 0.0; + index originCluster = none, targetCluster = none; + double cutUpdateToOriginCluster = 0.0, cutUpdateToTargetCluster = 0.0; + + Move(node n, double vol, index cc, index tc, double cuptoc, double cupttc) + : movedNode(n), volume(vol), originCluster(cc), targetCluster(tc), + cutUpdateToOriginCluster(cuptoc), cutUpdateToTargetCluster(cupttc) {} + }; + + static_assert(std::is_trivially_destructible::value, + "LouvainMapEquation::Move struct is not trivially destructible"); + + ParallelizationType parallelizationType; + bool parallel; + + bool hierarchical; + count maxIterations; + + std::vector clusterCut, clusterVolume; + double totalCut, totalVolume; + + // for RelaxMap + std::vector locks; + + // for SLM + Partition nextPartition; + std::vector> ets_neighborClusterWeights; + + count localMoving(std::vector &nodes, count iteration); + + count synchronousLocalMoving(std::vector &nodes, count iteration); + + bool tryLocalMove(node u, SparseVector &neighborClusterWeights, + std::vector &moves, bool synchronous); + + bool performMove(node u, double degree, double loopWeight, node currentCluster, + node targetCluster, double weightToTarget, double weightToCurrent); + + void aggregateAndApplyCutAndVolumeUpdates(std::vector &moves); + + void calculateInitialClusterCutAndVolume(); + + void runHierarchical(); + + /** + * Calculate the change in the map equation if the node is moved from its current cluster to the + * target cluster. To simplify the calculation, we remove terms that are constant for all target + * clusters. As a result, "moving" the node to its current cluster gives a value != 0, although + * the complete map equation would not change. + */ + double fitnessChange(node, double degree, double loopWeight, node currentCluster, + node targetCluster, double weightToTarget, double weightToCurrent, + double totalCutCurrently); + + count idivCeil(count a, count b) const { return (a + b - 1) / b; } + + std::pair chunkBounds(count i, count n, count chunkSize) const { + return std::make_pair(i * chunkSize, std::min(n, (i + 1) * chunkSize)); + } + +#ifndef NDEBUG + long double sumPLogPwAlpha = 0; + long double sumPLogPClusterCut = 0; + long double sumPLogPClusterCutPlusVol = 0; + double plogpRel(double w); + void updatePLogPSums(); + long double mapEquation(); + void checkUpdatedCutsAndVolumesAgainstRecomputation(); +#endif // NDEBUG +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_LOUVAIN_MAP_EQUATION_HPP_ diff --git a/vendor/include/networkit/community/Modularity.hpp b/vendor/include/networkit/community/Modularity.hpp new file mode 100644 index 0000000..396d73f --- /dev/null +++ b/vendor/include/networkit/community/Modularity.hpp @@ -0,0 +1,54 @@ +/* + * Modularity.hpp + * + * Created on: 10.12.2012 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_MODULARITY_HPP_ +#define NETWORKIT_COMMUNITY_MODULARITY_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * Modularity is a quality index for community detection. It assigns a quality value in [-0.5, 1.0] + * to a partition of a graph which is higher for more modular networks and partitions which better + * capture the modular structure. + * + * Modularity is defined as: + * + * $$mod(\\zeta) := \\frac{\\sum_{C \\in \\zeta} \\sum_{ e \\in E(C) } \\omega(e)}{\\sum_{e \\in E} + * \\omega(e)} + * \\frac{ \\sum_{C \\in \\zeta}( \\sum_{v \\in C} \\omega(v) )^2 }{4( \\sum_{e \\in E} \\omega(e) + * )^2 }$$ + */ +class Modularity final : public QualityMeasure { + +private: + double gTotalEdgeWeight; + +public: + /** Default constructor */ + Modularity(); + + /** + * Returns the Modularity of the given clustering with respect to the graph @a G. + * + * @param zeta The clustering. + * @param G The graph. + * @return The modularity. + */ + double getQuality(const Partition &zeta, const Graph &G) override; + + /** + * @param totalEdgeWeight Sum of all edge weights in @a G. If specified, it does not + * have to be computed. + */ + void setTotalEdgeWeight(double totalEdgeWeight); +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_MODULARITY_HPP_ diff --git a/vendor/include/networkit/community/NMIDistance.hpp b/vendor/include/networkit/community/NMIDistance.hpp new file mode 100644 index 0000000..be936b5 --- /dev/null +++ b/vendor/include/networkit/community/NMIDistance.hpp @@ -0,0 +1,28 @@ +/* + * NMIDistance.hpp + * + * Created on: 30.04.2013 + * Author: cls + */ + +#ifndef NETWORKIT_COMMUNITY_NMI_DISTANCE_HPP_ +#define NETWORKIT_COMMUNITY_NMI_DISTANCE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * NMIDistance quantifies the dissimilarity between two clusterings using + * Normalized Mutual Information. + * + */ +class NMIDistance final : public DissimilarityMeasure { + +public: + double getDissimilarity(const Graph &G, const Partition &zeta, const Partition &eta) override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_NMI_DISTANCE_HPP_ diff --git a/vendor/include/networkit/community/NodeStructuralRandMeasure.hpp b/vendor/include/networkit/community/NodeStructuralRandMeasure.hpp new file mode 100644 index 0000000..0da4017 --- /dev/null +++ b/vendor/include/networkit/community/NodeStructuralRandMeasure.hpp @@ -0,0 +1,27 @@ +/* + * NodeStructuralRandMeasure.hpp + * + * Created on: 19.01.2013 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_NODE_STRUCTURAL_RAND_MEASURE_HPP_ +#define NETWORKIT_COMMUNITY_NODE_STRUCTURAL_RAND_MEASURE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * The node-structural Rand measure assigns a similarity value in [0,1] + * to two partitions of a graph, by considering all pairs of nodes. + */ +class NodeStructuralRandMeasure final : public DissimilarityMeasure { + +public: + double getDissimilarity(const Graph &G, const Partition &zeta, const Partition &eta) override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_NODE_STRUCTURAL_RAND_MEASURE_HPP_ diff --git a/vendor/include/networkit/community/OverlappingCommunityDetectionAlgorithm.hpp b/vendor/include/networkit/community/OverlappingCommunityDetectionAlgorithm.hpp new file mode 100644 index 0000000..75f69b2 --- /dev/null +++ b/vendor/include/networkit/community/OverlappingCommunityDetectionAlgorithm.hpp @@ -0,0 +1,51 @@ +/* + * OverlappingCommunityDetectionAlgorithm.hpp + * + * Created on: 14.12.2020 + * Author: John Gelhausen + */ + +#ifndef NETWORKIT_COMMUNITY_OVERLAPPING_COMMUNITY_DETECTION_ALGORITHM_HPP_ +#define NETWORKIT_COMMUNITY_OVERLAPPING_COMMUNITY_DETECTION_ALGORITHM_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * Abstract base class for overlapping community detection/graph clustering algorithms. + */ +class OverlappingCommunityDetectionAlgorithm : public Algorithm { +public: + /** + * An overlapping community detection algorithm operates on a graph, so the constructor expects + * a graph. + * + * @param[in] G input graph + */ + OverlappingCommunityDetectionAlgorithm(const Graph &G); + + /** Default destructor */ + ~OverlappingCommunityDetectionAlgorithm() override = default; + + /** + * Apply algorithm to graph + */ + void run() override = 0; + + /** + * Returns the result of the run method or throws an error, if the algorithm hasn't run yet. + * @return cover of the node set + */ + const Cover &getCover() const; + +protected: + const Graph *G; + Cover result; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_OVERLAPPING_COMMUNITY_DETECTION_ALGORITHM_HPP_ diff --git a/vendor/include/networkit/community/OverlappingNMIDistance.hpp b/vendor/include/networkit/community/OverlappingNMIDistance.hpp new file mode 100644 index 0000000..efccd4f --- /dev/null +++ b/vendor/include/networkit/community/OverlappingNMIDistance.hpp @@ -0,0 +1,175 @@ +#ifndef NETWORKIT_COMMUNITY_OVERLAPPING_NMI_DISTANCE_HPP_ +#define NETWORKIT_COMMUNITY_OVERLAPPING_NMI_DISTANCE_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * Compare two covers using the overlapping normalized mutual information measure. This is a + * dissimilarity measure with a range of [0, 1]. A value of 0 indicates a perfect agreement while + * a 1 indicates complete disagreement. + * + * For the `MAX` normalization, this is the measure introduced in [NMI13]. Other normalization + * methods result in similar measures. + * + * Please note that non-overlapping NMIDistance uses another definition of the normalized mutual + * information. See NMIDistance for details on its computation. Both NMIDistance and + * OverlappingNMIDistance can be used with partitions, but produce different values. + * + * [NMI13] + * McDaid, Aaron F., Derek Greene, and Neil Hurley. + * “Normalized Mutual Information to Evaluate Overlapping Community Finding Algorithms.” + * ArXiv:1110.2515 [Physics], August 2, 2013. http://arxiv.org/abs/1110.2515. + */ +class OverlappingNMIDistance final : public DissimilarityMeasure { + +public: + enum Normalization { MIN, GEOMETRIC_MEAN, ARITHMETIC_MEAN, MAX, JOINT_ENTROPY }; + +private: + Normalization mNormalization{Normalization::MAX}; + +public: + OverlappingNMIDistance() = default; + + explicit OverlappingNMIDistance(Normalization normalization) : mNormalization(normalization) {} + + void setNormalization(Normalization normalization) { mNormalization = normalization; } + + double getDissimilarity(const Graph &G, const Partition &zeta, const Partition &eta) override; + double getDissimilarity(const Graph &G, const Cover &zeta, const Cover &eta) override; + +private: + struct SizesAndIntersections { + std::vector sizesX; + std::vector sizesY; + std::unordered_map, count, Aux::PairHash> intersectionSizes; + }; + + /** + * Calculating cluster sizes of covers and intersection sizes between two covers. + * + * @param X + * @param Y + * @return The cluster and intersection sizes of X and Y. + */ + static SizesAndIntersections + calculateClusterAndIntersectionSizes(const Graph &graph, const Cover &X, const Cover &Y); + + /** + * Calculates partial entropy. + * + * $$ + * h(w, n) = -w \log_2\left(\frac{w}{n}\right) + * $$ + * + * @param w Number of occurrences. + * @param n Total number of nodes. + * @return + */ + static double h(count w, count n); + + /** + * Calculates the entropy of a cluster. + * + * $$ + * H(X_i) = h(|\{ u | u \in X_i \}, n) + h(\{ u | u \notin X_i \}, n) + * $$ + * + * @param size Cluster size. + * @param n Total number of nodes. + * @return + */ + static double entropy(count size, count n); + + /** + * Calculates the entropy of a clustering. + * + * $$ + * H(X) = \sum_{X_i \in X} H(X_i) + * $$ + * + * @param sizesX The sizes of the clusters in X. + * @param n Total number of nodes. + * @return + */ + static double entropy(const std::vector &sizesX, count n); + + /** + * Calculates the adjusted conditional entropy between two clusters. + * + * $$ + * H^*(X_i|Y_j) = + * \begin{cases} + * H(X_i|Y_j), & \text{if $h(a, n) + h(d, n) \geq h(b, n) + h(c, n)$}\\ + * H(X_i), & \text{otherwise} + * \end{cases} + * $$ + * where + * $$ + * H(X_i|Y_j) &= H(X_i, Y_j) - H(Y_j)\\ + * &= h(a, n) + h(b, n) + h(c, n) + h(d, n) - h(b + d, n) - h(a + c, n), + * $$ + * $a = \sum_u \[X_{i,u} = 0 and Y_{j,u} = 0\]$, $b = \sum_u \[X_{i,u} = 0 and Y_{j,u} = 1\]$, + * $c = \sum_u \[X_{i,u} = 1 and Y_{j,u} = 0\]$ and $d = \sum_u \[X_{i,u} = 1 and Y_{j,u} = + * 1\]$. + * + * @param sizeXi Size of cluster X_i. + * @param sizeYj Size of cluster Y_j. + * @param intersectionSize Size of the intersection of X_i and Y_j. + * @param n Total number of nodes. + * @return + */ + static double adjustedConditionalEntropy(count sizeXi, count sizeYj, count intersectionSize, + count n); + + /** + * Calculates the entropy of the clustering X conditioned by the clustering Y. + * + * $$ + * H(X|Y) = \sum_{X_i \in X} \min_{Y_j \in Y} H^*(X_i|Y_j) + * $$ + * + * @param sizesX + * @param sizesY + * @param intersectionSizes + * A map which stores the the intersection size between clusters X[i] and Y[j] with indices + * i and j as keys. + * @param invertPairIndices + * Whether to invert the indices of the intersectionSizes map entries. + * This allows reusing the same map for H(X|Y) and H(Y|X). + * @param n Total number of nodes. + * @return + */ + static double conditionalEntropy( + const std::vector &sizesX, const std::vector &sizesY, + const std::unordered_map, count, Aux::PairHash> &intersectionSizes, + bool invertPairIndices, count n); + + static void clampBelow(double &value, double lowerBound, const char *format, + int printPrecision = 20); + + static void clampAbove(double &value, double upperBound, const char *format, + int printPrecision = 20); + + /** + * Normalize the given mutual information value. + * + * @param normalization + * @param mutualInformation + * @param entropyX + * @param entropyY + * @return + */ + static double normalize(OverlappingNMIDistance::Normalization normalization, + double mutualInformation, double entropyX, double entropyY); +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_OVERLAPPING_NMI_DISTANCE_HPP_ diff --git a/vendor/include/networkit/community/PLM.hpp b/vendor/include/networkit/community/PLM.hpp new file mode 100644 index 0000000..6300178 --- /dev/null +++ b/vendor/include/networkit/community/PLM.hpp @@ -0,0 +1,89 @@ +/* + * PLM.hpp + * + * Created on: 20.11.2013 + * Author: cls + */ + +#ifndef NETWORKIT_COMMUNITY_PLM_HPP_ +#define NETWORKIT_COMMUNITY_PLM_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * Parallel Louvain Method - a multi-level modularity maximizer. + */ +class PLM final : public CommunityDetectionAlgorithm { + +public: + /** + * @param[in] G input graph + * @param[in] refine add a second move phase to refine the communities + * @param[in] par parallelization strategy + * @param[in] gammamulti-resolution modularity parameter: + * 1.0 -> standard modularity + * 0.0 -> one community + * 2m -> singleton communities + * @param[in] maxIter maximum number of iterations for move phase + * @param[in] parallelCoarsening use parallel graph coarsening + * @param[in] turbo faster but uses O(n) additional memory per thread + * @param[in] recurse use recursive coarsening, see + * http://journals.aps.org/pre/abstract/10.1103/PhysRevE.89.049902 for some explanations + * (default: true) + * + */ + PLM(const Graph &G, bool refine = false, double gamma = 1.0, std::string par = "balanced", + count maxIter = 32, bool turbo = true, bool recurse = true); + + PLM(const Graph &G, const PLM &other); + + /** + * Detect communities. + */ + void run() override; + + /** + * Coarsens a graph based on a given partition and returns both the coarsened graph and a + * mapping for the nodes from fine to coarse. + * + * @param graph The input graph + * @param zeta Partition of the graph, which represents the desired state of the coarsened graph + * @return pair of coarsened graph and node-mappings from fine to coarse graph + */ + static std::pair> coarsen(const Graph &G, const Partition &zeta); + + /** + * Calculates a partition containing the mapping of node-id from a fine graph + * to a cluster-id from partition based on a coarse graph. + * + * @param Gcoarse Coarsened graph + * @param zetaCoarse Partition, which contains information about clusters in the coarsened graph + * @param Gfine Fine graph + * @param nodeToMetaNode mapping for node-id from fine to coarse graph + * @return Partition, which contains the cluster-id in the coarse graph for every node from the + * fine graph + */ + static Partition prolong(const Graph &Gcoarse, const Partition &zetaCoarse, const Graph &Gfine, + std::vector nodeToMetaNode); + + /** + * Returns fine-grained running time measurements for algorithm engineering purposes. + */ + const std::map> &getTiming() const; + +private: + std::string parallelism; + bool refine; + double gamma = 1.0; + count maxIter; + bool turbo; + bool recurse; + std::map> timing; // fine-grained running time measurement +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_COMMUNITY_PLM_HPP_ diff --git a/vendor/include/networkit/community/PLP.hpp b/vendor/include/networkit/community/PLP.hpp new file mode 100644 index 0000000..6e68f68 --- /dev/null +++ b/vendor/include/networkit/community/PLP.hpp @@ -0,0 +1,83 @@ +/* + * PLP.hpp + * + * Created on: 07.12.2012 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_PLP_HPP_ +#define NETWORKIT_COMMUNITY_PLP_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * As described in Ovelgoenne et al: An Ensemble Learning Strategy for Graph Clustering + * Raghavan et al. proposed a label propagation algorithm for graph clustering. + * This algorithm initializes every vertex of a graph with a unique label. Then, in iterative + * sweeps over the set of vertices the vertex labels are updated. A vertex gets the label + * that the maximum number of its neighbors have. The procedure is stopped when every vertex + * has the label that at least half of its neighbors have. + * + */ +class PLP final : public CommunityDetectionAlgorithm { + +private: + count updateThreshold = 0; + count maxIterations; + count nIterations = 0; //!< number of iterations in last run + std::vector timing; //!< running times for each iteration + +public: + /** + * Constructor to the label propagation community detection algorithm. + * + * @param[in] G input graph + * @param[in] theta updateThreshold: number of nodes that have to be changed in each iteration + * so that a new iteration starts. + */ + PLP(const Graph &G, count theta = none, count maxIterations = none); + + /** + * Constructor to the label propagation community detection algorithm. + * + * @param[in] G input graph + * @param[in] baseClustering optional; the algorithm will start from the given clustering. + * @param[in] theta updateThreshold: number of nodes that have to be changed in each iteration + * so that a new iteration starts. + */ + PLP(const Graph &G, const Partition &baseClustering, count theta = none); + + /** + * Run the label propagation clustering algorithm. + */ + void run() override; + + /** + * The algorithm runs until a number of nodes less than + * the threshold is updated. + * + * @param th The threshold. + */ + void setUpdateThreshold(count th); + + /** + * Get number of iterations in last run. + * + * @return The number of iterations. + */ + count numberOfIterations(); + + /** + * Get list of running times for each iteration. + * + * @return The list of running times in milliseconds + */ + const std::vector &getTiming() const; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_PLP_HPP_ diff --git a/vendor/include/networkit/community/ParallelAgglomerativeClusterer.hpp b/vendor/include/networkit/community/ParallelAgglomerativeClusterer.hpp new file mode 100644 index 0000000..ba2fdef --- /dev/null +++ b/vendor/include/networkit/community/ParallelAgglomerativeClusterer.hpp @@ -0,0 +1,37 @@ +/* + * ParallelAgglomerativeClusterer.hpp + * + * Created on: 30.10.2012 + * Author: Christian Staudt, Henning Meyerhenke + */ + +#ifndef NETWORKIT_COMMUNITY_PARALLEL_AGGLOMERATIVE_CLUSTERER_HPP_ +#define NETWORKIT_COMMUNITY_PARALLEL_AGGLOMERATIVE_CLUSTERER_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * A parallel agglomerative community detection algorithm, maximizing modularity. + */ +class ParallelAgglomerativeClusterer final : public CommunityDetectionAlgorithm { + +public: + /** + * Constructor to the parallel agglomerative clusterer. + * + * @param[in] G input graph + */ + ParallelAgglomerativeClusterer(const Graph &G); + + /** + * Detect communities. + */ + void run() override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_PARALLEL_AGGLOMERATIVE_CLUSTERER_HPP_ diff --git a/vendor/include/networkit/community/ParallelLeiden.hpp b/vendor/include/networkit/community/ParallelLeiden.hpp new file mode 100644 index 0000000..029d2b1 --- /dev/null +++ b/vendor/include/networkit/community/ParallelLeiden.hpp @@ -0,0 +1,96 @@ +#ifndef NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_HPP_ +#define NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace NetworKit { + +class ParallelLeiden final : public CommunityDetectionAlgorithm { +public: + /** + * @note As reported by Sahu et. al in "GVE-Leiden: Fast Leiden Algorithm for Community + * Detection in Shared Memory Setting", the current implementation in NetworKit might create a + * small fraction of disconnected communities. Since this violates the guarantees from the + * original algorithm, ParallelLeiden should be used with caution. In addition the modularity + * value of the resulting partition / clustering can be lower compared to other Leiden + * implementations and even Louvain. + * + * @param graph A networkit graph + * @param iterations Number of Leiden Iterations to be run + * @param randomize Randomize node order? + * @param gamma Resolution parameter + */ + explicit ParallelLeiden(const Graph &graph, int iterations = 3, bool randomize = true, + double gamma = 1); + + void run() override; + + int VECTOR_OVERSIZE = 10000; + +private: + inline double modularityDelta(double cutD, double degreeV, double volD) const { + return cutD - gamma * degreeV * volD * inverseGraphVolume; + }; + + inline double modularityThreshold(double cutC, double volC, double degreeV) const { + return cutC - gamma * (volC - degreeV) * degreeV * inverseGraphVolume; + } + + static inline void lockLowerFirst(index a, index b, std::vector &locks) { + if (a < b) { + locks[a].lock(); + locks[b].lock(); + } else { + locks[b].lock(); + locks[a].lock(); + } + } + + void flattenPartition(); + + void calculateVolumes(const Graph &graph); + + void parallelMove(const Graph &graph); + + Partition parallelRefine(const Graph &graph); + + double inverseGraphVolume; // 1/vol(V) + + std::vector communityVolumes; + + std::vector> mappings; + + static constexpr int WORKING_SIZE = 1000; + + double gamma; // Resolution parameter + + bool changed; + + int numberOfIterations; + + Aux::SignalHandler handler; + + bool random; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_HPP_ diff --git a/vendor/include/networkit/community/ParallelLeidenScoringExtension.hpp b/vendor/include/networkit/community/ParallelLeidenScoringExtension.hpp new file mode 100644 index 0000000..5c07db9 --- /dev/null +++ b/vendor/include/networkit/community/ParallelLeidenScoringExtension.hpp @@ -0,0 +1,68 @@ +/* + * ParallelLeidenScoringExtension.hpp + * + * Shared-library ABI for custom ParallelLeidenView move scoring metrics. + */ + +#ifndef NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_SCORING_EXTENSION_HPP_ +#define NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_SCORING_EXTENSION_HPP_ + +#include + +namespace NetworKit { + +using ParallelLeidenCommunityScoreFunction = + double (*)(double cutWeight, double degree, double communityVolume, count subsetSize, + count communitySize, double gamma, double inverseGraphVolume); + +using ParallelLeidenRefineSetConditionFunction = + bool (*)(double cutWeight, double subsetVolume, count subsetSize, double targetVolume, + count targetSize, double sourceVolume, count sourceSize, double gamma, + double inverseGraphVolume); + +} // namespace NetworKit + +extern "C" { + +/** + * Required: score a candidate community during the move phase. + */ +double networkitParallelLeidenCommunityScore(double cutWeight, double degree, double communityVolume, + NetworKit::count subsetSize, + NetworKit::count communitySize, double gamma, + double inverseGraphVolume); + +/** + * Optional: override the current-community stay threshold used to accept or reject the best move. + * When omitted, ParallelLeidenView falls back to the built-in modularity threshold. + */ +double networkitParallelLeidenCurrentCommunityThreshold(double cutWeight, double degree, + double communityVolume, + NetworKit::count subsetSize, + NetworKit::count communitySize, + double gamma, + double inverseGraphVolume); + +/** + * Optional: override the refine-phase R-set condition. + * When omitted, ParallelLeidenView falls back to the built-in modularity condition. + */ +bool networkitParallelLeidenRefineRSetCondition(double cutWeight, double subsetVolume, + NetworKit::count subsetSize, double targetVolume, + NetworKit::count targetSize, double sourceVolume, + NetworKit::count sourceSize, double gamma, + double inverseGraphVolume); + +/** + * Optional: override the refine-phase T-set condition. + * When omitted, ParallelLeidenView falls back to the built-in modularity condition. + */ +bool networkitParallelLeidenRefineTSetCondition(double cutWeight, double subsetVolume, + NetworKit::count subsetSize, double targetVolume, + NetworKit::count targetSize, double sourceVolume, + NetworKit::count sourceSize, double gamma, + double inverseGraphVolume); + +} // extern "C" + +#endif // NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_SCORING_EXTENSION_HPP_ diff --git a/vendor/include/networkit/community/ParallelLeidenView.hpp b/vendor/include/networkit/community/ParallelLeidenView.hpp new file mode 100644 index 0000000..2babe2e --- /dev/null +++ b/vendor/include/networkit/community/ParallelLeidenView.hpp @@ -0,0 +1,225 @@ +/* + * ParallelLeidenView.hpp + * + * Memory-efficient version of ParallelLeiden using CoarsenedGraphView + */ + +#ifndef NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_VIEW_HPP_ +#define NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_VIEW_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace NetworKit { + +/** + * Memory-efficient version of ParallelLeiden that uses CoarsenedGraphView + * instead of creating new graph structures, significantly reducing memory usage + * during the coarsening process. + */ +class ParallelLeidenView final : public CommunityDetectionAlgorithm { +public: + /** + * @note As reported by Sahu et. al in "GVE-Leiden: Fast Leiden Algorithm for Community + * Detection in Shared Memory Setting", the current implementation in NetworKit might create a + * small fraction of disconnected communities. Since this violates the guarantees from the + * original algorithm, ParallelLeidenView should be used with caution. In addition the + * modularity value of the resulting partition / clustering can be lower compared to other + * Leiden implementations and even Louvain. + * + * @param graph A networkit graph + * @param iterations Number of Leiden Iterations to be run + * @param randomize Randomize node order? + * @param gamma Resolution parameter + */ + explicit ParallelLeidenView(const Graph &graph, int iterations = 3, bool randomize = true, + double gamma = 1); + + ~ParallelLeidenView(); + + void run() override; + + /** + * Load a shared library that customizes the move-phase scoring metric. + * + * The library must export `networkitParallelLeidenCommunityScore`. It may additionally export + * `networkitParallelLeidenCurrentCommunityThreshold` to replace the default modularity-based + * stay threshold as well. + */ + void loadMoveScoringExtension(const std::string &sharedLibraryPath); + + void unloadMoveScoringExtension(); + + int VECTOR_OVERSIZE = 10000; + +private: + struct MoveStats { + count moved = 0; + count movedToSingleton = 0; + count marginalMovesRejected = 0; + double gainMarginSum = 0.0; + double gainMarginMin = std::numeric_limits::max(); + double gainMarginMax = std::numeric_limits::lowest(); + }; + + // Template interface to work with both Graph and CoarsenedGraphView + template + void calculateVolumes(const GraphType &graph); + + template + MoveStats parallelMove(const GraphType &graph); + + template + Partition parallelRefine(const GraphType &graph); + + static count nodeSize(const Graph &graph, node u); + + static count nodeSize(const CoarsenedGraphView &graph, node u); + + static double modularityCommunityScore(double cutD, double degreeV, double volD, + count subsetSize, count sizeD, double gamma, + double inverseGraphVolume) { + tlx::unused(subsetSize); + tlx::unused(sizeD); + return cutD - gamma * degreeV * volD * inverseGraphVolume; + } + + static double modularityThresholdScore(double cutC, double degreeV, double volC, + count subsetSize, count sizeC, double gamma, + double inverseGraphVolume) { + tlx::unused(subsetSize); + tlx::unused(sizeC); + return cutC - gamma * (volC - degreeV) * degreeV * inverseGraphVolume; + } + + static bool modularityRefineRSetCondition(double cutWeight, double subsetVolume, + count subsetSize, double targetVolume, + count targetSize, double sourceVolume, + count sourceSize, double gamma, + double inverseGraphVolume) { + tlx::unused(subsetSize); + tlx::unused(targetSize); + tlx::unused(sourceVolume); + tlx::unused(sourceSize); + return cutWeight >= gamma * subsetVolume * targetVolume * inverseGraphVolume; + } + + static bool modularityRefineTSetCondition(double cutWeight, double subsetVolume, + count subsetSize, double targetVolume, + count targetSize, double sourceVolume, + count sourceSize, double gamma, + double inverseGraphVolume) { + tlx::unused(subsetSize); + tlx::unused(targetSize); + tlx::unused(sourceVolume); + tlx::unused(sourceSize); + return cutWeight >= gamma * subsetVolume * targetVolume * inverseGraphVolume; + } + + inline double scoreCommunity(double cutWeight, double degree, double communityVolume, + count subsetSize, count communitySize) const { + return communityScoreFunction_(cutWeight, degree, communityVolume, subsetSize, + communitySize, gamma, inverseGraphVolume); + } + + inline double scoreCurrentCommunityThreshold(double cutWeight, double degree, + double communityVolume, count subsetSize, + count communitySize) const { + return currentCommunityThresholdFunction_(cutWeight, degree, communityVolume, subsetSize, + communitySize, gamma, inverseGraphVolume); + } + + inline bool refineRSetCondition(double cutWeight, double subsetVolume, count subsetSize, + double targetVolume, count targetSize, double sourceVolume, + count sourceSize) const { + return refineRSetConditionFunction_(cutWeight, subsetVolume, subsetSize, targetVolume, + targetSize, sourceVolume, sourceSize, gamma, + inverseGraphVolume); + } + + inline bool refineTSetCondition(double cutWeight, double subsetVolume, count subsetSize, + double targetVolume, count targetSize, double sourceVolume, + count sourceSize) const { + return refineTSetConditionFunction_(cutWeight, subsetVolume, subsetSize, targetVolume, + targetSize, sourceVolume, sourceSize, gamma, + inverseGraphVolume); + } + + static inline void lockLowerFirst(index a, index b, std::vector &locks) { + if (a < b) { + locks[a].lock(); + locks[b].lock(); + } else { + locks[b].lock(); + locks[a].lock(); + } + } + + void flattenPartition(); + + double inverseGraphVolume; // 1/vol(V) + + std::vector communityVolumes; + std::vector communitySizes; + + static constexpr int WORKING_SIZE = 1000; + + double gamma; // Resolution parameter + + bool changed; + + int numberOfIterations; + + Aux::SignalHandler handler; + + bool random; + + // Current coarsened graph view (only keep current, not all historical) + std::shared_ptr currentCoarsenedView; + + // Reject moves whose gain margin is too small (numerical-noise churn filter). + double moveGainMarginEpsilon = 1e-4; + + // Maximum inner iterations per Leiden iteration. + int maxInnerIterations = 20; + + // Optional convergence stop: minimum relative reduction in community count per inner iter. + // 0.0 disables this criterion. + double minCommunityReduction = 0.0; + + void *scoringExtensionHandle_ = nullptr; + ParallelLeidenCommunityScoreFunction communityScoreFunction_ = &modularityCommunityScore; + ParallelLeidenCommunityScoreFunction currentCommunityThresholdFunction_ = + &modularityThresholdScore; + ParallelLeidenRefineSetConditionFunction refineRSetConditionFunction_ = + &modularityRefineRSetCondition; + ParallelLeidenRefineSetConditionFunction refineTSetConditionFunction_ = + &modularityRefineTSetCondition; + std::string scoringExtensionPath_; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_PARALLEL_LEIDEN_VIEW_HPP_ diff --git a/vendor/include/networkit/community/PartitionFragmentation.hpp b/vendor/include/networkit/community/PartitionFragmentation.hpp new file mode 100644 index 0000000..904ebb4 --- /dev/null +++ b/vendor/include/networkit/community/PartitionFragmentation.hpp @@ -0,0 +1,30 @@ +#ifndef NETWORKIT_COMMUNITY_PARTITION_FRAGMENTATION_HPP_ +#define NETWORKIT_COMMUNITY_PARTITION_FRAGMENTATION_HPP_ + +#include + +namespace NetworKit { + +/** + * This measure evaluates how fragmented a partition is. The fragmentation of a single cluster is + * defined as one minus the number of nodes in its maximum connected components divided by its total + * number of nodes. Smaller values thus indicate a smaller fragmentation. + */ +class PartitionFragmentation final : public LocalPartitionEvaluation { +public: + using LocalPartitionEvaluation::LocalPartitionEvaluation; + + /** + * Execute the algorithm. The algorithm is not parallel. + */ + void run() override; + + /** + * @return true - smaller values are better than larger values. + */ + bool isSmallBetter() const override { return true; }; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_PARTITION_FRAGMENTATION_HPP_ diff --git a/vendor/include/networkit/community/PartitionHubDominance.hpp b/vendor/include/networkit/community/PartitionHubDominance.hpp new file mode 100644 index 0000000..b249870 --- /dev/null +++ b/vendor/include/networkit/community/PartitionHubDominance.hpp @@ -0,0 +1,37 @@ +#ifndef NETWORKIT_COMMUNITY_PARTITION_HUB_DOMINANCE_HPP_ +#define NETWORKIT_COMMUNITY_PARTITION_HUB_DOMINANCE_HPP_ + +#include + +namespace NetworKit { + +/** + * A quality measure that measures the dominance of hubs in clusters. The hub dominance of a single + * cluster is defined as the maximum cluster-internal degree of a node in that cluster divided by + * the maximum cluster-internal degree, i.e. the number of nodes in the cluster minus one. The + * value for all clusters is defined as the average of all clusters. + * Strictly speaking this is not a quality measure as this is rather dependent on the type of the + * considered graph, for more information see + * Lancichinetti A, Kivel M, Saramki J, Fortunato S (2010) + * Characterizing the Community Structure of Complex Networks + * PLoS ONE 5(8): e11976. doi: 10.1371/journal.pone.0011976 + * http://www.plosone.org/article/info%3Adoi%2F10.1371%2Fjournal.pone.0011976 + */ +class PartitionHubDominance final : public LocalPartitionEvaluation { +public: + using LocalPartitionEvaluation::LocalPartitionEvaluation; + + /** + * Execute the algorithm. The algorithm is not parallel. + */ + void run() override; + + /** + * @return false - small values are not better, large values indicate better cluster cohesion. + */ + bool isSmallBetter() const override { return false; } +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_PARTITION_HUB_DOMINANCE_HPP_ diff --git a/vendor/include/networkit/community/PartitionIntersection.hpp b/vendor/include/networkit/community/PartitionIntersection.hpp new file mode 100644 index 0000000..27fd093 --- /dev/null +++ b/vendor/include/networkit/community/PartitionIntersection.hpp @@ -0,0 +1,25 @@ +#ifndef NETWORKIT_COMMUNITY_PARTITION_INTERSECTION_HPP_ +#define NETWORKIT_COMMUNITY_PARTITION_INTERSECTION_HPP_ + +#include + +namespace NetworKit { + +/** + * Class for calculating the intersection of two partitions, i.e. the clustering with the fewest + * clusters such that each cluster is a subset of a cluster in both partitions. + */ +class PartitionIntersection final { +public: + /** + * Calculate the intersection of two partitions @a zeta and @a eta + * @param zeta The first partition + * @param eta The second partition + * @return The intersection of @a zeta and @a eta + */ + Partition calculate(const Partition &zeta, const Partition &eta); +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_COMMUNITY_PARTITION_INTERSECTION_HPP_ diff --git a/vendor/include/networkit/community/QualityMeasure.hpp b/vendor/include/networkit/community/QualityMeasure.hpp new file mode 100644 index 0000000..38a4350 --- /dev/null +++ b/vendor/include/networkit/community/QualityMeasure.hpp @@ -0,0 +1,27 @@ +/* + * QualityMeasure.hpp + * + * Created on: 10.12.2012 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_COMMUNITY_QUALITY_MEASURE_HPP_ +#define NETWORKIT_COMMUNITY_QUALITY_MEASURE_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup community + * Abstract base class for all clustering quality measures. + */ +class QualityMeasure { + +public: + virtual double getQuality(const Partition &zeta, const Graph &G) = 0; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_QUALITY_MEASURE_HPP_ diff --git a/vendor/include/networkit/community/SampledGraphStructuralRandMeasure.hpp b/vendor/include/networkit/community/SampledGraphStructuralRandMeasure.hpp new file mode 100644 index 0000000..b028975 --- /dev/null +++ b/vendor/include/networkit/community/SampledGraphStructuralRandMeasure.hpp @@ -0,0 +1,40 @@ +/* + * SampledGraphStructuralRandMeasure.hpp + * + * Created on: 01.07.2013 + * Author: cls + */ + +#ifndef NETWORKIT_COMMUNITY_SAMPLED_GRAPH_STRUCTURAL_RAND_MEASURE_HPP_ +#define NETWORKIT_COMMUNITY_SAMPLED_GRAPH_STRUCTURAL_RAND_MEASURE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * The graph-structural Rand measure assigns a similarity value in [0,1] + * to two partitions of a graph, by considering connected pairs of nodes. + * This implementation approximates the index by sampling. + */ +class SampledGraphStructuralRandMeasure final : public DissimilarityMeasure { + +public: + /** + * Constructs the SampledGraphStructuralRandMeasure. A maximum of @a maxSamples samples are + * drawn. + * + * @param maxSamples The amount of samples to draw. + */ + SampledGraphStructuralRandMeasure(count maxSamples); + + double getDissimilarity(const Graph &G, const Partition &first, + const Partition &second) override; + +private: + count maxSamples; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_SAMPLED_GRAPH_STRUCTURAL_RAND_MEASURE_HPP_ diff --git a/vendor/include/networkit/community/SampledNodeStructuralRandMeasure.hpp b/vendor/include/networkit/community/SampledNodeStructuralRandMeasure.hpp new file mode 100644 index 0000000..78c6704 --- /dev/null +++ b/vendor/include/networkit/community/SampledNodeStructuralRandMeasure.hpp @@ -0,0 +1,40 @@ +/* + * SampledNodeStructuralRandMeasure.hpp + * + * Created on: 01.07.2013 + * Author: cls + */ + +#ifndef NETWORKIT_COMMUNITY_SAMPLED_NODE_STRUCTURAL_RAND_MEASURE_HPP_ +#define NETWORKIT_COMMUNITY_SAMPLED_NODE_STRUCTURAL_RAND_MEASURE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup community + * The node-structural Rand measure assigns a similarity value in [0,1] + * to two partitions of a graph, by considering pairs of nodes. + * This implementation approximates the index by sampling. + */ +class SampledNodeStructuralRandMeasure final : public DissimilarityMeasure { + +public: + /** + * Constructs the SampledNodeStructuralRandMeasure. A maximum of @a maxSamples samples are + * drawn. + * + * @param maxSamples The amount of samples to draw. + */ + SampledNodeStructuralRandMeasure(count maxSamples); + + double getDissimilarity(const Graph &G, const Partition &first, + const Partition &second) override; + +private: + count maxSamples; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMMUNITY_SAMPLED_NODE_STRUCTURAL_RAND_MEASURE_HPP_ diff --git a/vendor/include/networkit/community/StablePartitionNodes.hpp b/vendor/include/networkit/community/StablePartitionNodes.hpp new file mode 100644 index 0000000..7ebcc24 --- /dev/null +++ b/vendor/include/networkit/community/StablePartitionNodes.hpp @@ -0,0 +1,48 @@ +#ifndef NETWORKIT_COMMUNITY_STABLE_PARTITION_NODES_HPP_ +#define NETWORKIT_COMMUNITY_STABLE_PARTITION_NODES_HPP_ + +#include + +namespace NetworKit { + +/** + * Evaluates how stable a given partition is. A node is considered to be stable if it has strictly + * more connections to its own partition than to other partitions. Isolated nodes are considered to + * be stable. The value of a cluster is the percentage of stable nodes in the cluster. Larger values + * indicate that a clustering is more stable and thus better defined. + */ +class StablePartitionNodes final : public LocalPartitionEvaluation { +public: + using LocalPartitionEvaluation::LocalPartitionEvaluation; // inherit constructor + + /** + * Execute the algorithm. + */ + void run() override; + + /** + * Check if a given node is stable, i.e. more connected to its own partition than to other + * partitions. + * + * @param u The node to check + * @return If the node @a u is stable. + */ + bool isStable(node u) const { + assureFinished(); + return static_cast(stableMarker[u]); + }; + + /** + * If small values are better. Here large values are better. + * + * @return false. + */ + bool isSmallBetter() const override { return false; } + +private: + std::vector stableMarker; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMMUNITY_STABLE_PARTITION_NODES_HPP_ diff --git a/vendor/include/networkit/components/BiconnectedComponents.hpp b/vendor/include/networkit/components/BiconnectedComponents.hpp new file mode 100644 index 0000000..0152e5f --- /dev/null +++ b/vendor/include/networkit/components/BiconnectedComponents.hpp @@ -0,0 +1,116 @@ +/* + * BiconnectedeComponents.hpp + * + * Created on: March 2018 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_COMPONENTS_BICONNECTED_COMPONENTS_HPP_ +#define NETWORKIT_COMPONENTS_BICONNECTED_COMPONENTS_HPP_ + +#include +#include +#include + +#include +#include + +namespace NetworKit { + +/* + * @ingroup components + * Determines the biconnected components of an undirected graph as defined in + * Tarjan, Robert. Depth-First Search and Linear Graph Algorithms. SIAM J. + * Comput. Vol 1, No. 2, June 1972. + */ +class BiconnectedComponents final : public Algorithm { + +public: + /* + * Creates BiconnectedComponents class for Graph @a G. + * + * @param G The graph. + */ + BiconnectedComponents(const Graph &G); + + /* + * This method determines the biconnected components for the graph given in + * the constructor. + */ + void run() override; + + /* + * Get the number of biconnected components. + * + * @return The number of biconnected components. + */ + count numberOfComponents() const; + + /* + * Get the size of each component. + * + * @return Map from component index to size. + */ + std::map getComponentSizes() const; + + /* + * Get the components vector. + * + * @return Vector of vectors, each component is stored as an (unordered) set + * of nodes. + */ + std::vector> getComponents() const; + + /* + * Get the components that contain node @a u. + * + * @param u A node. + * @return Components that contain node @a u. + */ + const std::unordered_set &getComponentsOfNode(node u) const { + assureFinished(); + return componentsOfNode[u]; + } + +private: + void init(); + void newComponent(std::pair e); + + const Graph *G; + count n; + count idx; + count nComp; + std::vector level; + std::vector lowpt; + std::vector parent; + std::vector visited; + std::vector isRoot; + std::vector> componentsOfNode; + std::map componentSizes; +}; + +inline count BiconnectedComponents::numberOfComponents() const { + assureFinished(); + return nComp; +} + +inline std::map BiconnectedComponents::getComponentSizes() const { + assureFinished(); + return componentSizes; +} + +inline std::vector> BiconnectedComponents::getComponents() const { + assureFinished(); + std::vector> result(nComp); + + node v = 0; + for (auto components : componentsOfNode) { + for (auto it = components.begin(); it != components.end(); ++it) { + result[*it].push_back(v); + } + ++v; + } + return result; +} +} // namespace NetworKit +#endif // NETWORKIT_COMPONENTS_BICONNECTED_COMPONENTS_HPP_ diff --git a/vendor/include/networkit/components/ComponentDecomposition.hpp b/vendor/include/networkit/components/ComponentDecomposition.hpp new file mode 100644 index 0000000..209f8f7 --- /dev/null +++ b/vendor/include/networkit/components/ComponentDecomposition.hpp @@ -0,0 +1,72 @@ +/* + * ComponentDecomposition.hpp + * + * Created on: 17.12.2020 + * Author: cls, + * Eugenio Angriman + */ + +#ifndef NETWORKIT_COMPONENTS_COMPONENT_DECOMPOSITION_HPP_ +#define NETWORKIT_COMPONENTS_COMPONENT_DECOMPOSITION_HPP_ + +#include +#include + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup components + * Abstract class for algorithms that compute the components of a graph. + */ +class ComponentDecomposition : public Algorithm { +public: + /** + * Constructs the ComponentDecomposition class for the given Graph @a G. + * + * @param G The graph. + */ + ComponentDecomposition(const Graph &G); + + /** + * Get the number of connected components. + * + * @return The number of connected components. + */ + count numberOfComponents() const; + + /** + * Get the component in which node @a u is situated. + * + * @param[in] u The node whose component is asked for. + */ + count componentOfNode(node u) const; + + /** + * Get a Partition that represents the components. + * + * @return A partition representing the found components. + */ + const Partition &getPartition() const; + + /** + * Return the map from component to size + */ + std::map getComponentSizes() const; + + /** + * @return Vector of components, each stored as (unordered) set of nodes. + */ + std::vector> getComponents() const; + +protected: + const Graph *G; + Partition component; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMPONENTS_COMPONENT_DECOMPOSITION_HPP_ diff --git a/vendor/include/networkit/components/ConnectedComponents.hpp b/vendor/include/networkit/components/ConnectedComponents.hpp new file mode 100644 index 0000000..1ba8b3e --- /dev/null +++ b/vendor/include/networkit/components/ConnectedComponents.hpp @@ -0,0 +1,55 @@ +/* + * ConnectedComponents.hpp + * + * Created on: Dec 16, 2013 + * Author: cls + */ + +#ifndef NETWORKIT_COMPONENTS_CONNECTED_COMPONENTS_HPP_ +#define NETWORKIT_COMPONENTS_CONNECTED_COMPONENTS_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +// pImpl +namespace ConnectedComponentsDetails { +template +class ConnectedComponentsImpl; +} // namespace ConnectedComponentsDetails + +class ConnectedComponents final : public ComponentDecomposition { +public: + /* Creates the ConnectedComponents class for graph @G. + * + * @param G The graph. + */ + ConnectedComponents(const Graph &G); + + ~ConnectedComponents() override; + + /* + * Computes the connected components of the input graph. + */ + void run() override; + + /** + * Constructs a new graph that contains only the nodes inside the largest + * connected component. + * @param G The input graph. + * @param compactGraph If true, the node ids of the output graph will be compacted + * (i.e. re-numbered from 0 to n-1). If false, the node ids will not be changed. + * @return The largest connected component of the input graph @a G. + */ + static GraphW extractLargestConnectedComponent(const Graph &G, bool compactGraph = false); + +private: + std::unique_ptr> impl; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMPONENTS_CONNECTED_COMPONENTS_HPP_ diff --git a/vendor/include/networkit/components/DynConnectedComponents.hpp b/vendor/include/networkit/components/DynConnectedComponents.hpp new file mode 100644 index 0000000..90841ef --- /dev/null +++ b/vendor/include/networkit/components/DynConnectedComponents.hpp @@ -0,0 +1,71 @@ +/* + * DynConnectedComponents.hpp + * + * Created on: June 2017 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_COMPONENTS_DYN_CONNECTED_COMPONENTS_HPP_ +#define NETWORKIT_COMPONENTS_DYN_CONNECTED_COMPONENTS_HPP_ + +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +// pImpl +namespace DynConnectedComponentsDetails { +template +class DynConnectedComponentsImpl; +} // namespace DynConnectedComponentsDetails + +/** + * @ingroup components + * Determines and updates the connected components of an undirected graph. + */ +class DynConnectedComponents final : public ComponentDecomposition, public DynAlgorithm { + +public: + /** + * Create ConnectedComponents class for Graph @a G. + * + * @param G The graph. + */ + DynConnectedComponents(const Graph &G); + + ~DynConnectedComponents() override; + + /** + * Finds the connected components of the input graph. + */ + void run() override; + + /** + * Updates the connected components after an edge insertion or deletion. + * + * @param[in] event The event that happened (edge deletion or + * insertion). + */ + void update(GraphEvent e) override; + + /** + * Updates the connected components after a batch of edge insertions or + * deletions. + * + * @param[in] batch A vector that contains a batch of edge insertions or + * deletions. + */ + void updateBatch(const std::vector &batch) override; + +private: + std::unique_ptr> impl; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMPONENTS_DYN_CONNECTED_COMPONENTS_HPP_ diff --git a/vendor/include/networkit/components/DynWeaklyConnectedComponents.hpp b/vendor/include/networkit/components/DynWeaklyConnectedComponents.hpp new file mode 100644 index 0000000..0a7e6c8 --- /dev/null +++ b/vendor/include/networkit/components/DynWeaklyConnectedComponents.hpp @@ -0,0 +1,73 @@ +/* + * DynWeaklyConnectedComponents.hpp + * + * Created on: June 20, 2017 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_COMPONENTS_DYN_WEAKLY_CONNECTED_COMPONENTS_HPP_ +#define NETWORKIT_COMPONENTS_DYN_WEAKLY_CONNECTED_COMPONENTS_HPP_ + +#include + +#include +#include +#include +#include + +namespace NetworKit { + +// pImpl +namespace DynConnectedComponentsDetails { +template +class DynConnectedComponentsImpl; +} // namespace DynConnectedComponentsDetails + +/** + * @ingroup components + * Determines and updates the weakly connected components of a directed + * graph. + */ +class DynWeaklyConnectedComponents final : public ComponentDecomposition, public DynAlgorithm { + +public: + /** + * Create DynWeaklyConnectedComponents class for Graph @a G. + * + * @param G The graph. + */ + DynWeaklyConnectedComponents(const Graph &G); + + ~DynWeaklyConnectedComponents() override; + + /** + * This method determines the weakly connected components for the graph + * given in the constructor. + */ + void run() override; + + /** + * Updates the weakly connected components after an edge insertion or + * deletion. + * + * @param[in] event The event that happened (edge insertion + * or deletion). + */ + void update(GraphEvent event) override; + + /** + * Updates the weakly connected components after a batch of edge events + * (insertions or deletions). + * + * @param[in] batch A vector that contains a batch of edge events + * (insertions or deletions). + */ + void updateBatch(const std::vector &batch) override; + +private: + std::unique_ptr> impl; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMPONENTS_DYN_WEAKLY_CONNECTED_COMPONENTS_HPP_ diff --git a/vendor/include/networkit/components/ParallelConnectedComponents.hpp b/vendor/include/networkit/components/ParallelConnectedComponents.hpp new file mode 100644 index 0000000..24cc4b5 --- /dev/null +++ b/vendor/include/networkit/components/ParallelConnectedComponents.hpp @@ -0,0 +1,44 @@ +/* + * ConnectedComponents.cpp + * + * Created on: Dec 16, 2013 + * Author: cls + */ + +#ifndef NETWORKIT_COMPONENTS_PARALLEL_CONNECTED_COMPONENTS_HPP_ +#define NETWORKIT_COMPONENTS_PARALLEL_CONNECTED_COMPONENTS_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup components + * Determines the connected components of an undirected graph. + */ +class ParallelConnectedComponents final : public ComponentDecomposition { +public: + /** + * @param[in] G Graph for which connected components shall be computed. + * @param[in] coarsening Specifies whether the main algorithm based on + * label propagation (LP) shall work recursively (true) or not (false) by + * coarsening/contracting an LP-computed clustering. Defaults to true + * since we saw positive effects in terms of running time for many networks. + * Beware of possible memory implications. + */ + ParallelConnectedComponents(const Graph &G, bool coarsening = true); + + /** + * This method determines the connected components for the graph g. + */ + void run() override; + +private: + bool coarsening; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMPONENTS_PARALLEL_CONNECTED_COMPONENTS_HPP_ diff --git a/vendor/include/networkit/components/RandomSpanningForest.hpp b/vendor/include/networkit/components/RandomSpanningForest.hpp new file mode 100644 index 0000000..d8077b9 --- /dev/null +++ b/vendor/include/networkit/components/RandomSpanningForest.hpp @@ -0,0 +1,36 @@ +/* + * RandomSpanningForest.hpp + * + * Created on: 06.09.2015 + * Author: Henning + */ + +#ifndef NETWORKIT_COMPONENTS_RANDOM_SPANNING_FOREST_HPP_ +#define NETWORKIT_COMPONENTS_RANDOM_SPANNING_FOREST_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * Creates a random spanning tree for each connected component. + * Time complexity: cover time of G. + * @ingroup graph + */ +class RandomSpanningForest final : public SpanningForest { +public: + RandomSpanningForest(const Graph &G); + + ~RandomSpanningForest() override = default; + + /** + * Computes for each component a random spanning tree. + * Uses simple random-walk based algorithm. + * Time complexity: cover time of G. + */ + void run() override; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_COMPONENTS_RANDOM_SPANNING_FOREST_HPP_ diff --git a/vendor/include/networkit/components/StronglyConnectedComponents.hpp b/vendor/include/networkit/components/StronglyConnectedComponents.hpp new file mode 100644 index 0000000..8cb66fa --- /dev/null +++ b/vendor/include/networkit/components/StronglyConnectedComponents.hpp @@ -0,0 +1,50 @@ +/* + * StronglyConnectedComponents.hpp + * + * Created on: 01.06.2014 + * Authors: Klara Reichard + * Marvin Ritter + * Obada Mahdi + * Eugenio Angriman + */ + +#ifndef NETWORKIT_COMPONENTS_STRONGLY_CONNECTED_COMPONENTS_HPP_ +#define NETWORKIT_COMPONENTS_STRONGLY_CONNECTED_COMPONENTS_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup components + */ +class StronglyConnectedComponents final : public ComponentDecomposition { + +public: + /** + * Determines the strongly connected components of a directed graph using Tarjan's algorithm. + * + * @param G Graph A directed graph. + */ + StronglyConnectedComponents(const Graph &G); + + /** + * Runs the algorithm. + */ + void run() override; + + /** + * Constructs a new graph that contains only the nodes inside the largest + * strongly connected component. + * @param G The input graph. + * @param compactGraph If true, the node ids of the output graph will be compacted + * (i.e. re-numbered from 0 to n-1). If false, the node ids will not be changed. + */ + static GraphW extractLargestStronglyConnectedComponent(const Graph &G, + bool compactGraph = false); +}; + +} // namespace NetworKit + +#endif // NETWORKIT_COMPONENTS_STRONGLY_CONNECTED_COMPONENTS_HPP_ diff --git a/vendor/include/networkit/components/WeaklyConnectedComponents.hpp b/vendor/include/networkit/components/WeaklyConnectedComponents.hpp new file mode 100644 index 0000000..3d997ae --- /dev/null +++ b/vendor/include/networkit/components/WeaklyConnectedComponents.hpp @@ -0,0 +1,59 @@ +/* + * WeaklyConnectedComponents.hpp + * + * Created on: June 20, 2017 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_COMPONENTS_WEAKLY_CONNECTED_COMPONENTS_HPP_ +#define NETWORKIT_COMPONENTS_WEAKLY_CONNECTED_COMPONENTS_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +// pImpl +namespace ConnectedComponentsDetails { +template +class ConnectedComponentsImpl; +} // namespace ConnectedComponentsDetails + +/** + * @ingroup components + * Determines the weakly connected components of a directed graph. + */ +class WeaklyConnectedComponents final : public ComponentDecomposition { +public: + /** + * Create WeaklyConnectedComponents class for Graph @a G. + * + * @param G The graph. + */ + WeaklyConnectedComponents(const Graph &G); + + ~WeaklyConnectedComponents() override; + + /* + * Computes the weakly connected components of the input graph. + */ + void run() override; + + /** + * Constructs a new graph that contains only the nodes inside the largest + * weakly connected component. + * @param G The input graph. + * @param compactGraph If true, the node ids of the output graph will be compacted + * (i.e. re-numbered from 0 to n-1). If false, the node ids will not be changed. + * @return The largest weakly connected component of the input graph @a G. + */ + static GraphW extractLargestWeaklyConnectedComponent(const Graph &G, bool compactGraph = false); + +private: + std::unique_ptr> impl; +}; +} // namespace NetworKit + +#endif // NETWORKIT_COMPONENTS_WEAKLY_CONNECTED_COMPONENTS_HPP_ diff --git a/vendor/include/networkit/correlation/Assortativity.hpp b/vendor/include/networkit/correlation/Assortativity.hpp new file mode 100644 index 0000000..8a26795 --- /dev/null +++ b/vendor/include/networkit/correlation/Assortativity.hpp @@ -0,0 +1,64 @@ +/* + * Assortativity.hpp + * + * Created on: Jun 13, 2015 + * Author: Christian Staudt + */ + +#ifndef NETWORKIT_CORRELATION_ASSORTATIVITY_HPP_ +#define NETWORKIT_CORRELATION_ASSORTATIVITY_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup correlation + * + * Assortativity computes a coefficient that expresses the correlation of a + * node attribute among connected pairs of nodes. + */ +class Assortativity final : public Algorithm { + +public: + /** + * Initialize Assortativity with a graph @a G and an array of numerical + * node values. + * + * @param G The graph. + * @param attribute numerical node value array + */ + Assortativity(const Graph &G, const std::vector &attribute); + + /** + * Initialize Assortativity with a graph @a G and a partition of the node set + * + * @param G The graph. + * @param partition partition of the node set + */ + Assortativity(const Graph &G, const Partition &partition); + + /** + * Runs the algorithm. The algorithm is not parallel. + */ + void run() override; + + /** + * Return the assortativity coefficient. + */ + double getCoefficient() const; + +private: + const Graph *G; + const std::vector emptyVector; + const Partition emptyPartition; + const std::vector *attribute; + const Partition *partition; + bool nominal; // whether we calculate assortativity for a nominal or ordinal attribute + double coefficient; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_CORRELATION_ASSORTATIVITY_HPP_ diff --git a/vendor/include/networkit/distance/APSP.hpp b/vendor/include/networkit/distance/APSP.hpp new file mode 100644 index 0000000..b3600bb --- /dev/null +++ b/vendor/include/networkit/distance/APSP.hpp @@ -0,0 +1,70 @@ +/* + * APSP.hpp + * + * Created on: 07.07.2015 + * Author: Arie Slobbe + */ + +#ifndef NETWORKIT_DISTANCE_APSP_HPP_ +#define NETWORKIT_DISTANCE_APSP_HPP_ + +#include + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Class for all-pair shortest path algorithm. + */ +class APSP : public Algorithm { + +public: + /** + * Creates the APSP class for @a G. + * + * @param G The graph. + */ + APSP(const Graph &G); + + ~APSP() override = default; + + /** + * Computes the shortest paths from each node to all other nodes. + * The algorithm is parallel. + */ + void run() override; + + /** + * Returns a vector of weighted distances between node pairs. + * + * @return The shortest-path distances from each node to any other node in + * the graph. + */ + const std::vector> &getDistances() const { + assureFinished(); + return distances; + } + + /** + * Returns the distance from u to v or infinity if u and v are not + * connected. + * + */ + edgeweight getDistance(node u, node v) const { + assureFinished(); + return distances[u][v]; + } + +protected: + const Graph &G; + std::vector> distances; + std::vector> sssps; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_APSP_HPP_ diff --git a/vendor/include/networkit/distance/AStar.hpp b/vendor/include/networkit/distance/AStar.hpp new file mode 100644 index 0000000..6f2e77e --- /dev/null +++ b/vendor/include/networkit/distance/AStar.hpp @@ -0,0 +1,68 @@ +/* + * AStar.hpp + * + * Created on: 09.08.2019 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_DISTANCE_A_STAR_HPP_ +#define NETWORKIT_DISTANCE_A_STAR_HPP_ + +#include + +/** + * @ingroup distance + * AStar path-finding algoritm + */ +namespace NetworKit { +class AStar final : public STSP { +public: + /** + * Creates the AStarGeneral class for the graph @a G, the source node @a + * source, and the target node @a target using a template parameter as + * heuristic function. + * + * @param G The graph. + * @param distanceHeu Vector with a lower bound of the distance from every + * node to the target. + * @param source The source node. + * @param target The target node. + * @param storePred If true, the algorithm will also store the predecessors + * and reconstruct a shortest path from @a source and @a target. + */ + AStar(const Graph &G, const std::vector &distanceHeu, node source, node target, + bool storePred = true) + : STSP(G, source, target, storePred), + astar(AStarGeneral(G, Heuristic(distanceHeu), source, target, storePred)) { + if (G.upperNodeIdBound() != distanceHeu.size()) { + throw std::runtime_error("Error: G.upperNodeIdBound() must be equal to " + "the size of distanceHeu."); + } + } + + /* + * Executes the AStar algorithm. + */ + void run() override { + astar.run(); + distance = astar.getDistance(); + hasRun = true; + } + + std::vector getPath() const override { return astar.getPath(); } + +private: + struct Heuristic { + public: + Heuristic(const std::vector &distanceHeu) : distanceHeu(distanceHeu) {} + double operator()(node u) const noexcept { return distanceHeu[u]; } + + private: + const std::vector &distanceHeu; + }; + + AStarGeneral astar; +}; +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_A_STAR_HPP_ diff --git a/vendor/include/networkit/distance/AStarGeneral.hpp b/vendor/include/networkit/distance/AStarGeneral.hpp new file mode 100644 index 0000000..5077171 --- /dev/null +++ b/vendor/include/networkit/distance/AStarGeneral.hpp @@ -0,0 +1,110 @@ +/* + * AStarGeneral.hpp + * + * Created on: 09.08.2019 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_DISTANCE_A_STAR_GENERAL_HPP_ +#define NETWORKIT_DISTANCE_A_STAR_GENERAL_HPP_ + +#include + +#include +#include + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * AStar path-finding algoritm with general Heuristic function. + */ +template +class AStarGeneral final : public STSP { +public: + /** + * Creates the AStarGeneral class for the graph @a G, the source node @a + * source, and the target node @a target using a template parameter as + * heuristic function. + * + * @param G The graph. + * @param heu Heuristic function that takes a node as input and returns a + * lower bound of the distance of that node to the target node. + * @param source The source node. + * @param target The target node. + * @param storePred If true, the algorithm will also store the predecessors + * and reconstruct a shortest path from @a source and @a target. + */ + AStarGeneral(const Graph &G, Heuristic heu, node source, node target, bool storePred = true) + : STSP(G, source, target, storePred), heu(heu), heap{prio} {} + + /* + * Executes the AStar algorithm. + */ + void run() override { + if (source == target) { + distance = 0.; + hasRun = true; + return; + } + + init(); + constexpr auto infdist = std::numeric_limits::max(); + const count n = G->upperNodeIdBound(); + distance = infdist; + + std::ranges::fill(distFromSource, infdist); + distFromSource.resize(n, infdist); + distFromSource[source] = 0.; + + std::ranges::fill(prio, infdist); + prio.resize(n, infdist); + prio[source] = 0.; + + heap.clear(); + heap.reserve(n); + heap.push(source); + + node top = none; + do { + top = heap.extract_top(); + if (top == target) { + distance = distFromSource[target]; + break; + } + + G->forNeighborsOf(top, [&](node u, edgeweight w) { + const double newDist = distFromSource[top] + w; + if (newDist < distFromSource[u]) { + distFromSource[u] = newDist; + prio[u] = newDist + heu(u); + heap.update(u); + if (storePred) { + pred[u] = top; + } + } + }); + } while (!heap.empty()); + + if (top != target) { + WARN("Source cannot reach target!"); + } else if (storePred) { + buildPath(); + } + + hasRun = true; + } + +private: + // Priorities used for the heap + std::vector distFromSource, prio; + // Lower bound of the distance to the target node + Heuristic heu; + + tlx::d_ary_addressable_int_heap> heap; +}; +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_A_STAR_GENERAL_HPP_ diff --git a/vendor/include/networkit/distance/AdamicAdarDistance.hpp b/vendor/include/networkit/distance/AdamicAdarDistance.hpp new file mode 100644 index 0000000..992c77b --- /dev/null +++ b/vendor/include/networkit/distance/AdamicAdarDistance.hpp @@ -0,0 +1,52 @@ +/* + * AdamicAdarDistance.hpp + * + * Created on: 18.11.2014 + * Author: Michael Hamann, Gerd Lindner + */ + +#ifndef NETWORKIT_DISTANCE_ADAMIC_ADAR_DISTANCE_HPP_ +#define NETWORKIT_DISTANCE_ADAMIC_ADAR_DISTANCE_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * An implementation of the Adamic Adar distance measure. + */ +class AdamicAdarDistance final : public NodeDistance { + +private: + std::vector aaDistance; // result vector + +public: + /** + * @param G The graph. + */ + AdamicAdarDistance(const GraphW &G); + + /** + * Computes the Adamic Adar distances of all connected pairs of nodes. + * REQ: Needs to be called before distance() and getEdgeScores() deliver meaningful results! + */ + void preprocess() override; + + /** + * Returns the Adamic Adar distance between node @a u and node @a v. + * @return Adamic Adar distance between the two nodes. + */ + double distance(node u, node v) override; + + /** + * Returns the Adamic Adar distances between all connected nodes. + * @return Vector containing the Adamic Adar distances between all connected pairs of nodes. + */ + const std::vector &getEdgeScores() const override; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_ADAMIC_ADAR_DISTANCE_HPP_ diff --git a/vendor/include/networkit/distance/AffectedNodes.hpp b/vendor/include/networkit/distance/AffectedNodes.hpp new file mode 100644 index 0000000..12fbf0f --- /dev/null +++ b/vendor/include/networkit/distance/AffectedNodes.hpp @@ -0,0 +1,130 @@ +/* + * File: AffectedNodes.hpp + * Author: paddya + * + * Created on 17. Dezember 2016, 16:35 + */ + +#ifndef NETWORKIT_DISTANCE_AFFECTED_NODES_HPP_ +#define NETWORKIT_DISTANCE_AFFECTED_NODES_HPP_ + +#include +#include +#include + +namespace NetworKit { + +class AffectedNodes : public Algorithm { +public: + /** + * Constructs the AffectedNodes class for a given graph @a G and a graph event + * @a event. The run() method computes the set of affected nodes, + * their distance to the edge modification and, in the case of an edge insertion, + * an upper bound for the improvement of the harmonic closeness centrality + * of each affected node. + * + * @param G The graph. + * @param event The graph event. + */ + AffectedNodes(const Graph &G, const GraphEvent &event); + /** + * Computes the set of affected nodes. + */ + void run() override; + /** + * Returns the set of affected nodes. + * + * @return The set of affected nodes + */ + std::vector getNodes(); + /** + * Returns the distances to the edge modification for each node. + * + * @return The distances to the edge modification for each node + */ + std::vector getDistances(); + /** + * Returns the level-based improvement bounds for each affected node. + * + * @return The improvement upper bound for each affected node, indexed by node ID + */ + std::vector getImprovements(); + + edgeweight closenessU = 0; + edgeweight closenessV = 0; + edgeweight improvementU = 0; + edgeweight improvementV = 0; + +private: + /** + * Handles an edge insertion. + */ + void addedEdge(); + /** + * Handles an edge removal. + */ + void removedEdge(); + /** + * Runs a complete BFS from @a source while ignoring the edge between + * @a source and @a startNeighbor. This is equivalent to running a + * BFS in G $\\setminus$ (source, startNeighbor). + * + * @param source The source node. + * @param startNeighbor The neighbor node to be ignored on level 1. + * @return The distances of each node to @a source. + */ + std::vector bfsWithoutStartNeighbor(node source, node startNeighbor); + + /** + * Runs a complete reverse BFS from @a source while ignoring the edge between + * @a startNeighbor and @a source. This is equivalent to running a + * BFS in G - (source, startNeighbor). + * + * @param source The source node. + * @param startNeighbor The neighbor node to be ignored on level 1. + * @return The distances of each node to @a source. + */ + std::vector reverseBfsWithoutStartNeighbor(node source, node startNeighbor); + + /** + * Runs a BFS from @a source while optionally including an edge between + * @a source and @a additionalStartNeighbor. This is equivalent to running + * a BFS from @a source in G + (source, additionalStartNeighbor). + * + * The algorithm prunes a subtree if it encounters a node @a w for which + * the new distance is not smaller than the distance in @a distances. + * + * @param source The source node. + * @param distances The distances without the additional edge. + * @param additionalStartNeighbor The additional start neighbor. + * @return The distances of each node to @a source. + */ + std::pair, std::vector> + getAffectedNodes(node source, std::vector &distances, + node additionalStartNeighbor = none); + + /** + * Runs a reverse BFS from @a source while optionally including an edge between + * @a additionalStartNeighbor and @a source. This is equivalent to running + * a BFS from @a source in G + (source, additionalStartNeighbor). + * + * The algorithm prunes a subtree if it encounters a node @a w for which + * the new distance is not smaller than the distance in @a distances. + * + * @param source The source node. + * @param distances The distances without the additional edge. + * @param additionalStartNeighbor The additional start neighbor. + * @return The distances of each node to @a source. + */ + std::pair, std::vector> + getAffectedNodesBackwards(node source, std::vector &distances, + node additionalStartNeighbor = none); + const Graph &G; + const GraphEvent &event; + std::vector nodes; + std::vector distances; + std::vector improvements; +}; +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_AFFECTED_NODES_HPP_ diff --git a/vendor/include/networkit/distance/AlgebraicDistance.hpp b/vendor/include/networkit/distance/AlgebraicDistance.hpp new file mode 100644 index 0000000..5752e08 --- /dev/null +++ b/vendor/include/networkit/distance/AlgebraicDistance.hpp @@ -0,0 +1,63 @@ +/* + * AlgebraicDistance.hpp + * + * Created on: 03.11.2015 + * Author: Henning Meyerhenke, Christian Staudt, Michael Hamann + */ + +#ifndef NETWORKIT_DISTANCE_ALGEBRAIC_DISTANCE_HPP_ +#define NETWORKIT_DISTANCE_ALGEBRAIC_DISTANCE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Algebraic distance assigns a distance value to pairs of nodes + * according to their structural closeness in the graph. + * Algebraic distances will become small within dense subgraphs. + */ +class AlgebraicDistance final : public NodeDistance { + +public: + /** + * @param G The graph. + * @param numberSystems Number of vectors/systems used for algebraic iteration. + * @param numberIterations Number of iterations in each system. + * @param omega attenuation factor influencing convergence speed. + * @param norm The norm factor of the extended algebraic distance. + * @param withEdgeScores calculate array of scores for edges {u,v} that equal ad(u,v) + */ + AlgebraicDistance(const Graph &G, count numberSystems = 10, count numberIterations = 30, + double omega = 0.5, index norm = 0, bool withEdgeScores = false); + + void preprocess() override; + + /** + * @return algebraic distance between the two nodes. + */ + double distance(node u, node v) override; + + const std::vector &getEdgeScores() const override; + +private: + /** + * initialize vectors randomly + */ + void randomInit(); + + count numSystems; //!< number of vectors/systems used for algebraic iteration + count numIters; //!< number of iterations in each system + double omega; //!< attenuation factor influencing the speed of convergence + index norm; + const index MAX_NORM = 0; + bool withEdgeScores; + + std::vector loads; //!< loads[u*numSystems..(u+1)*numSystems]: loads for node u + + std::vector edgeScores; //!< distance(u,v) for edge {u,v} +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_DISTANCE_ALGEBRAIC_DISTANCE_HPP_ diff --git a/vendor/include/networkit/distance/BFS.hpp b/vendor/include/networkit/distance/BFS.hpp new file mode 100644 index 0000000..63eb965 --- /dev/null +++ b/vendor/include/networkit/distance/BFS.hpp @@ -0,0 +1,43 @@ +/* + * BFS.hpp + * + * Created on: Jul 23, 2013 + * Author: Henning + */ + +#ifndef NETWORKIT_DISTANCE_BFS_HPP_ +#define NETWORKIT_DISTANCE_BFS_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * The BFS class is used to do a breadth-first search on a Graph from a given + * source node. + */ +class BFS final : public SSSP { + +public: + /** + * Constructs the BFS class for @a G and source node @a source. + * + * @param G The graph + * @param source The source node of the breadth-first search + * @param storePaths Paths are reconstructable and the number of paths is + * stored. + * @param storeNodesSortedByDistance Store a vector of nodes ordered in + * increasing distance from the source. + * @param target The target node. + */ + BFS(const Graph &G, node source, bool storePaths = true, + bool storeNodesSortedByDistance = false, node target = none); + + /** + * Breadth-first search from @a source. + */ + void run() override; +}; +} /* namespace NetworKit */ +#endif // NETWORKIT_DISTANCE_BFS_HPP_ diff --git a/vendor/include/networkit/distance/BidirectionalBFS.hpp b/vendor/include/networkit/distance/BidirectionalBFS.hpp new file mode 100644 index 0000000..3c4b25e --- /dev/null +++ b/vendor/include/networkit/distance/BidirectionalBFS.hpp @@ -0,0 +1,51 @@ +/* + * BidirectionalBFS.hpp + * + * Created on: 14.06.2019 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_DISTANCE_BIDIRECTIONAL_BFS_HPP_ +#define NETWORKIT_DISTANCE_BIDIRECTIONAL_BFS_HPP_ + +#include + +#include + +namespace NetworKit { + +/* + * @ingroup distance + * Implements a bidirectional breadth-first search on a graph from two given source and target + * nodes. Explores the graph from both the source and target nodes until the two explorations meet. + */ +class BidirectionalBFS final : public STSP { + +public: + /** + * Creates the BidirectionalBFS class for a graph @a G, source node @a source, and + * target node @a target. + * + * @param G The graph. + * @param source The source node. + * @param target The target node. + * @param storePred If true, the algorithm will also store the predecessors + * and reconstruct a shortest path from @a source and @a target. + */ + BidirectionalBFS(const Graph &G, node source, node target, bool storePred = true) + : STSP(G, source, target, storePred) {} + + /* + * Perform a bidirectional BFS from the given source and target nodes. + */ + void run() override; + +private: + std::vector visited; + uint8_t ts = 0; + static constexpr uint8_t ballMask = uint8_t(1) << 7; + std::queue sQueue, sQueueNext, tQueue, tQueueNext; +}; +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_BIDIRECTIONAL_BFS_HPP_ diff --git a/vendor/include/networkit/distance/BidirectionalDijkstra.hpp b/vendor/include/networkit/distance/BidirectionalDijkstra.hpp new file mode 100644 index 0000000..e7d55ae --- /dev/null +++ b/vendor/include/networkit/distance/BidirectionalDijkstra.hpp @@ -0,0 +1,69 @@ +/* + * BidirectionalDijkstra.hpp + * + * Created on: 14.06.2019 + * Author: Eugenio Angriman + */ + +#ifndef NETWORKIT_DISTANCE_BIDIRECTIONAL_DIJKSTRA_HPP_ +#define NETWORKIT_DISTANCE_BIDIRECTIONAL_DIJKSTRA_HPP_ + +#include +#include + +#include + +namespace NetworKit { + +/* + * @ingroup distance + * Bidirectional implementation of the Dijkstra algorithm from two given source and target nodes. + * Explores the graph from both the source and target nodes until the two explorations meet. + */ +class BidirectionalDijkstra final : public STSP { + +public: + /** + * Creates the BidirectionalDijkstra class for a graph @a G, source node @a source, and + * target node @a target. + * + * @param G The graph. + * @param source The source node. + * @param target The target node. + * @param storePred If true, the algorithm will also store the predecessors + * and reconstruct a shortest path from @a source and @a target. + */ + BidirectionalDijkstra(const Graph &G, node source, node target, bool storePred = true) + : STSP(G, source, target, storePred) {} + + /* + * Runs the bidirectional Dijkstra algorithm. + */ + void run() override; + +private: + std::vector dist1; + std::vector dist2; + std::vector predT; + std::vector visited; + uint8_t ts = 0; + static constexpr uint8_t ballMask = uint8_t(1) << 7; + + void buildPaths(std::stack> &pathStack); + + struct CompareST { + public: + CompareST(const std::vector &d1, const std::vector &d2) + : d1(d1), d2(d2) {} + bool operator()(node u, node v) { return d1[u] + d2[u] < d1[v] + d2[v]; } + + private: + const std::vector &d1, &d2; + }; + + tlx::d_ary_addressable_int_heap> h1{dist1}; + tlx::d_ary_addressable_int_heap> h2{dist2}; + tlx::d_ary_addressable_int_heap stH{CompareST(dist1, dist2)}; +}; +} // namespace NetworKit +#endif // NETWORKIT_DISTANCE_BIDIRECTIONAL_DIJKSTRA_HPP_ diff --git a/vendor/include/networkit/distance/CommuteTimeDistance.hpp b/vendor/include/networkit/distance/CommuteTimeDistance.hpp new file mode 100644 index 0000000..021a340 --- /dev/null +++ b/vendor/include/networkit/distance/CommuteTimeDistance.hpp @@ -0,0 +1,89 @@ +/* + * CommuteTimeDistance.hpp + * + * Created on: 12.04.2016 + * Author: ebergamini + */ + +#ifndef NETWORKIT_DISTANCE_COMMUTE_TIME_DISTANCE_HPP_ +#define NETWORKIT_DISTANCE_COMMUTE_TIME_DISTANCE_HPP_ + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup centrality + * + * CommuteTimeDistance edge centrality. + * + */ +class CommuteTimeDistance final : public Algorithm { + +public: + /** + * Constructs the CommuteTimeDistance class for the given Graph @a G. + * @param G The graph. + * @param tol The tolerance used for the approximation + */ + CommuteTimeDistance(const Graph &G, double tol = 0.1); + + /** + * Destructor. + */ + ~CommuteTimeDistance() override = default; + + /** + * Computes ECTD exactly. + */ + void run() override; + + /** + * Computes approximation by projection. + */ + void runApproximation(); + + /** + * Computes approximation by projection, in parallel. + */ + void runParallelApproximation(); + + /** + * @return The elapsed time to setup the solver in milliseconds. + */ + uint64_t getSetupTime() const; + + /** + * Returns the commute time distance between node @a u and node @a v. + * This method does not need the initial preprocessing (no need to call the run() method). + * @return commute time distance between the two nodes. + */ + + double runSinglePair(node u, node v); + + /** + * Returns the commute time distance between node @a u and node @a v. + * @return commute time distance between the two nodes. Needs to call run() or + * runApproximation() first. + */ + double distance(node u, node v); + + double runSingleSource(node u); + +protected: + const Graph *G; + double tol; + Lamg lamg; + uint64_t setupTime; + std::vector> distances; + std::vector solutions; + bool exactly; + count k; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_COMMUTE_TIME_DISTANCE_HPP_ diff --git a/vendor/include/networkit/distance/Diameter.hpp b/vendor/include/networkit/distance/Diameter.hpp new file mode 100644 index 0000000..c7eec2b --- /dev/null +++ b/vendor/include/networkit/distance/Diameter.hpp @@ -0,0 +1,97 @@ +/* + * Diameter.hpp + * + * Created on: 19.02.2014 + * Author: Daniel Hoske, Christian Staudt + */ + +#ifndef NETWORKIT_DISTANCE_DIAMETER_HPP_ +#define NETWORKIT_DISTANCE_DIAMETER_HPP_ + +#include +#include +#include + +namespace NetworKit { +enum DiameterAlgo { + AUTOMATIC, + EXACT, + ESTIMATED_RANGE, + ESTIMATED_SAMPLES, + ESTIMATED_PEDANTIC, + automatic = AUTOMATIC, // this + following added for backwards compatibility + exact = EXACT, + estimatedRange = ESTIMATED_RANGE, + estimatedSamples = ESTIMATED_SAMPLES, + estimatedPedantic = ESTIMATED_PEDANTIC +}; + +/** + * @ingroup distance + */ +class Diameter final : public Algorithm { + +public: + Diameter(const Graph &G, DiameterAlgo algo = DiameterAlgo::AUTOMATIC, double error = -1.f, + count nSamples = 0); + + void run() override; + + std::pair getDiameter() const; + +private: + const Graph *G; + DiameterAlgo algo; + double error; + count nSamples; + std::pair diameterBounds; + + /** + * Get the estimation of the diameter of the graph @a G. The algorithm is based on the + * ExactSumSweep algorithm presented in Michele Borassi, Pierluigi Crescenzi, Michel Habib, + * Walter A. Kosters, Andrea Marino, Frank W. Takes, Fast diameter and radius BFS-based + * computation in (weakly connected) real-world graphs: With an application to the six degrees + * of separation games, Theoretical Computer Science, Volume 586, 27 June 2015, Pages 59-80, + * ISSN 0304-3975, http://dx.doi.org/10.1016/j.tcs.2015.02.033. + * (http://www.sciencedirect.com/science/article/pii/S0304397515001644) + * @param G The graph. + * @param error The maximum allowed relative error. Set to 0 for the exact diameter. + * @return Pair of lower and upper bound for diameter. + */ + std::pair estimatedDiameterRange(const Graph &G, double error); + + /** + * Get the exact diameter of the graph @a G. The algorithm for unweighted graphs is the same as + * the algorithm for the estimated diameter range with error 0. + * + * @param G The graph. + * @return exact diameter of the graph @a G + */ + edgeweight exactDiameter(const Graph &G); + + /** + * Get a 2-approximation of the node diameter (unweighted diameter) of @a G. + * + * @param[in] G The graph. + * @param[in] samples One sample is enough if the graph is connected. If there + * are multiple connected components, then the number of samples + * must be chosen so that the probability of sampling the component + * with the largest diameter is high. + * @return A 2-approximation of the vertex diameter (unweighted diameter) of @a G. + */ + edgeweight estimatedVertexDiameter(const Graph &G, count samples); + + /** @return a 2-approximation of the vertex diameter (unweighted diameter) of @a G. + Considers each connected component and returns the maximum diameter. + */ + edgeweight estimatedVertexDiameterPedantic(const Graph &G); + + /** @return a 2-approximation of the vertex diameter (unweighted diameter) of @a G. + Considers each connected component and returns the maximum diameter. + */ + edgeweight estimatedVertexDiameterPedantic2(const Graph &G); +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_DIAMETER_HPP_ diff --git a/vendor/include/networkit/distance/Dijkstra.hpp b/vendor/include/networkit/distance/Dijkstra.hpp new file mode 100644 index 0000000..d26307e --- /dev/null +++ b/vendor/include/networkit/distance/Dijkstra.hpp @@ -0,0 +1,50 @@ +/* + * Dijkstra.hpp + * + * Created on: Jul 23, 2013 + * Author: Henning, Christian Staudt + */ + +#ifndef NETWORKIT_DISTANCE_DIJKSTRA_HPP_ +#define NETWORKIT_DISTANCE_DIJKSTRA_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Dijkstra's SSSP algorithm. + */ +class Dijkstra final : public SSSP { + +public: + /** + * Creates the Dijkstra class for @a G and the source node @a source. + * + * @param G The graph. + * @param source The source node. + * @param storePaths Paths are reconstructable and the number of paths is + * stored. + * @param storeNodesSortedByDistance Store a vector of nodes ordered in + * increasing distance from the source. + * @param target The target node. + */ + Dijkstra(const Graph &G, node source, bool storePaths = true, + bool storeNodesSortedByDistance = false, node target = none); + + /** + * Performs the Dijkstra SSSP algorithm on the graph given in the + * constructor. + */ + void run() override; + +private: + tlx::d_ary_addressable_int_heap> heap; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_DISTANCE_DIJKSTRA_HPP_ diff --git a/vendor/include/networkit/distance/DynAPSP.hpp b/vendor/include/networkit/distance/DynAPSP.hpp new file mode 100644 index 0000000..09f12d9 --- /dev/null +++ b/vendor/include/networkit/distance/DynAPSP.hpp @@ -0,0 +1,67 @@ +/* + * DynAPSP.hpp + * + * Created on: 12.08.2015 + * Author: Arie Slobbe, Elisabetta Bergamini + */ + +#ifndef NETWORKIT_DISTANCE_DYN_APSP_HPP_ +#define NETWORKIT_DISTANCE_DYN_APSP_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Dynamic APSP. + */ +class DynAPSP : public APSP, public DynAlgorithm { + +public: + /** + * Creates the object for @a G. + * + * @param G The graph. + */ + DynAPSP(const Graph &G); + + /** initialize distances and Pred by repeatedly running the Dijkstra2 algorithm */ + void run() override; + + /** + * Updates the pairwise distances after an edge insertions on the graph. + * Notice: it works only with edge insertions. + * + * @param e The edge insertions. + */ + void update(GraphEvent e) override; + + /** + * Updates the pairwise distances after a batch of edge insertions on the graph. + * Notice: it works only with edge insertions. + * + * @param batch The batch of edge insertions. + */ + void updateBatch(const std::vector &batch) override; + + /** Returns number of visited pairs */ + count visPairs(); + + /** + * Returns a vector containing a shortest path from node u to node v, and an empty path if u and + * v are not connected. + * + */ + std::vector getPath(node u, node v); + +private: +private: + count visitedPairs = 0; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_DYN_APSP_HPP_ diff --git a/vendor/include/networkit/distance/DynBFS.hpp b/vendor/include/networkit/distance/DynBFS.hpp new file mode 100644 index 0000000..27d83c0 --- /dev/null +++ b/vendor/include/networkit/distance/DynBFS.hpp @@ -0,0 +1,56 @@ +/* + * DynBFS.hpp + * + * Created on: 17.07.2014 + * Author: cls, ebergamini + */ + +#ifndef NETWORKIT_DISTANCE_DYN_BFS_HPP_ +#define NETWORKIT_DISTANCE_DYN_BFS_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Dynamic breadth-first search. + */ +class DynBFS final : public DynSSSP { + + static constexpr edgeweight infDist = std::numeric_limits::max(); + +public: + /** + * Creates the object for @a G and source @a s. + * + * @param G The graph. + * @param s The source node. + * @param storePredecessors keep track of the lists of predecessors? + */ + DynBFS(const Graph &G, node s, bool storePredecessors = true); + + void run() override; + + /** Updates the distances after an edge insertion.*/ + void update(GraphEvent e) override; + + /** Updates the distances after a batch of edge insertions.*/ + void updateBatch(const std::vector &batch) override; + + /* Returns the number of shortest paths to node t.*/ + bigfloat getNumberOfPaths(node t) const; + +private: + enum Color { WHITE, BLACK, GRAY }; + std::vector color; + count maxDistance; +}; + +inline bigfloat DynBFS::getNumberOfPaths(node t) const { + return npaths[t]; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_DYN_BFS_HPP_ diff --git a/vendor/include/networkit/distance/DynDijkstra.hpp b/vendor/include/networkit/distance/DynDijkstra.hpp new file mode 100644 index 0000000..def0e94 --- /dev/null +++ b/vendor/include/networkit/distance/DynDijkstra.hpp @@ -0,0 +1,57 @@ +/* + * DynDijkstra.hpp + * + * Created on: 21.07.2014 + * Author: ebergamini + */ + +#ifndef NETWORKIT_DISTANCE_DYN_DIJKSTRA_HPP_ +#define NETWORKIT_DISTANCE_DYN_DIJKSTRA_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Dynamic Dijkstra. + */ +class DynDijkstra final : public DynSSSP { + +public: + /** + * Creates the object for @a G and source @a s. + * + * @param G The graph. + * @param s The source node. + * @param storePredecessors keep track of the lists of predecessors? + */ + DynDijkstra(const Graph &G, node s, bool storePredecessors = true); + + // TODO the run method could take a vector of distances as an input and in that case just use + // those distances instead of computing dijkstra from scratch + void run() override; + + /** Updates the distances after an edge insertion.*/ + void update(GraphEvent e) override; + + /** Updates the distances after a batch of edge insertions.*/ + void updateBatch(const std::vector &batch) override; + +private: + enum Color { WHITE, GRAY, BLACK }; + std::vector color; + static constexpr edgeweight infDist = std::numeric_limits::max(); + static constexpr edgeweight distEpsilon = 0.000001; + + tlx::d_ary_addressable_int_heap> heap; + std::vector updateDistances; + tlx::d_ary_addressable_int_heap> updateHeap; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_DYN_DIJKSTRA_HPP_ diff --git a/vendor/include/networkit/distance/DynPrunedLandmarkLabeling.hpp b/vendor/include/networkit/distance/DynPrunedLandmarkLabeling.hpp new file mode 100644 index 0000000..fae0b36 --- /dev/null +++ b/vendor/include/networkit/distance/DynPrunedLandmarkLabeling.hpp @@ -0,0 +1,67 @@ +#ifndef NETWORKIT_DISTANCE_DYN_PRUNED_LANDMARK_LABELING_HPP_ +#define NETWORKIT_DISTANCE_DYN_PRUNED_LANDMARK_LABELING_HPP_ + +#include +#include + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Dynamic pruned landmark labeling. + */ +class DynPrunedLandmarkLabeling final : public PrunedLandmarkLabeling, public DynAlgorithm { + +public: + /** + * Dynamic Pruned Landmark Labeling algorithm based on the paper "Fully Dynamic 2-Hop Cover + * Labeling " from D'Angelo et al., ACM JEA 2019. The algorithm computes distance labels by + * performing pruned breadth-first searches from each vertex. Distance labels can be updated + * efficiently after edge insertions. + * @note this algorithm ignores edge weights and only supports edge insertions. + * + * @param G The input graph. + */ + DynPrunedLandmarkLabeling(const Graph &G) : PrunedLandmarkLabeling(G) {} + + ~DynPrunedLandmarkLabeling() override = default; + + /** + * Updates the distance labels after an edge insertion on the graph. + * @note supports only edge insertions. + * + * @param e The edge insertion. + */ + void update(GraphEvent e) override; + + /** + * Not implemented. The algorithm does not support batch updates. + * @note This function is not implemented. + */ + void updateBatch(const std::vector &) override { + throw std::runtime_error("Not implemented."); + } + +private: + /** + * Updates the distance labels after an edge insertion. + * @param u Source node of the edge. + * @param v Target node of the edge. + */ + void addEdge(node u, node v); + + void prunedBFS(node k, node startNode, count bfsLevel, bool reverse); + + void sortUpdatedLabels(bool reverse); + + std::vector updatedNodes; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_DYN_PRUNED_LANDMARK_LABELING_HPP_ diff --git a/vendor/include/networkit/distance/DynSSSP.hpp b/vendor/include/networkit/distance/DynSSSP.hpp new file mode 100644 index 0000000..360ae8b --- /dev/null +++ b/vendor/include/networkit/distance/DynSSSP.hpp @@ -0,0 +1,87 @@ +/* + * DynSSSP.hpp + * + * Created on: 17.07.2014 + * Author: cls, ebergamini + */ + +#ifndef NETWORKIT_DISTANCE_DYN_SSSP_HPP_ +#define NETWORKIT_DISTANCE_DYN_SSSP_HPP_ + +#include + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Interface for dynamic single-source shortest path algorithms. + */ +class DynSSSP : public SSSP, public DynAlgorithm { + + friend class DynApproxBetweenness; + +public: + /** + * The algorithm computes a dynamic SSSP starting from the specified + * source vertex. + * + * @param graph input graph. + * @param source source vertex. + * @param storePredecessors keep track of the lists of predecessors? + */ + DynSSSP(const Graph &G, node source, bool storePredecessors = true, node target = none); + + ~DynSSSP() override = default; + + /** + * Returns true or false depending on whether the node previoulsy specified + * with setTargetNode has been modified by the udate or not. + * + * @param batch The batch of edge insertions. + */ + bool modified(); + /** + * Set a target node to be `observed` during the update. If a node t is set as + * target before the update, the function modified() will return true or false + * depending on whether node t has been modified by the update. + * + * @param t Node to be `observed`. + */ + void setTargetNode(node t = 0); + + /** + * Returns the predecessor nodes of @a t on all shortest paths from source to @a t. + * @param t Target node. + * @return The predecessors of @a t on all shortest paths from source to @a t. + */ + const std::vector &getPredecessors(node t) const; + +protected: + bool storePreds = true; + bool mod = false; + node target; +}; + +inline bool DynSSSP::modified() { + return mod; +} + +inline void DynSSSP::setTargetNode(const node t) { + target = t; +} + +inline const std::vector &DynSSSP::getPredecessors(node t) const { + if (!storePreds) { + throw std::runtime_error("predecessors have not been stored"); + } + return previous[t]; +} + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_DYN_SSSP_HPP_ diff --git a/vendor/include/networkit/distance/Eccentricity.hpp b/vendor/include/networkit/distance/Eccentricity.hpp new file mode 100644 index 0000000..546c473 --- /dev/null +++ b/vendor/include/networkit/distance/Eccentricity.hpp @@ -0,0 +1,32 @@ +/* + * Eccentricity.hpp + * + * Created on: 19.02.2014 + * Author: cls + */ + +#ifndef NETWORKIT_DISTANCE_ECCENTRICITY_HPP_ +#define NETWORKIT_DISTANCE_ECCENTRICITY_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * The eccentricity of a node `u` is defined as the distance to the farthest + * node from `u`. In other words, it is the longest shortest-path starting from + * node `u`. + */ +class Eccentricity { + +public: + /** + * @return The farthest node v, and the length of the shortest path to v. + */ + static std::pair getValue(const Graph &G, node u); +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_ECCENTRICITY_HPP_ diff --git a/vendor/include/networkit/distance/EffectiveDiameter.hpp b/vendor/include/networkit/distance/EffectiveDiameter.hpp new file mode 100644 index 0000000..4b52ed1 --- /dev/null +++ b/vendor/include/networkit/distance/EffectiveDiameter.hpp @@ -0,0 +1,47 @@ +/* + * EffectiveDiameter.hpp + * + * Created on: 16.06.2014 + * Author: Marc Nemes + */ + +#ifndef NETWORKIT_DISTANCE_EFFECTIVE_DIAMETER_HPP_ +#define NETWORKIT_DISTANCE_EFFECTIVE_DIAMETER_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + */ +class EffectiveDiameter final : public Algorithm { + +public: + /** + * Computes the effective diameter exactly. + * The effective diameter is defined as the number of edges on average to reach \p ratio of all + * other nodes. + * @param G the given graph + * @param ratio the ratio of nodes that should be connected (0,1], default = 0.9 + */ + EffectiveDiameter(const Graph &G, double ratio = 0.9); + + void run() override; + + /** + * Returns the exact effective diameter of the graph. + * @return the exact effective diameter of the graph + */ + double getEffectiveDiameter() const; + +private: + const Graph *G; + const double ratio; + double effectiveDiameter; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_EFFECTIVE_DIAMETER_HPP_ diff --git a/vendor/include/networkit/distance/EffectiveDiameterApproximation.hpp b/vendor/include/networkit/distance/EffectiveDiameterApproximation.hpp new file mode 100644 index 0000000..d0997ad --- /dev/null +++ b/vendor/include/networkit/distance/EffectiveDiameterApproximation.hpp @@ -0,0 +1,57 @@ +/* + * EffectiveDiameterApproximation.hpp + * + * Created on: 29.03.16 + * Author: Maximilian Vogel + */ + +#ifndef NETWORKIT_DISTANCE_EFFECTIVE_DIAMETER_APPROXIMATION_HPP_ +#define NETWORKIT_DISTANCE_EFFECTIVE_DIAMETER_APPROXIMATION_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + */ +class EffectiveDiameterApproximation final : public Algorithm { + +public: + /** + * Approximates the effective diameter of a given graph. + * The effective diameter is defined as the number of edges on average to reach \p ratio of all + * other nodes. Implementation after the ANF algorithm presented in the paper "A Fast and + * Scalable Tool for Data Mining in Massive Graphs"[1] + * + * [1] by Palmer, Gibbons and Faloutsos which can be found here: + * http://www.cs.cmu.edu/~christos/PUBLICATIONS/kdd02-anf.pdf + * + * @param G the given graph + * @param ratio the ratio of nodes that should be connected (0,1]; default = 0.9 + * @param k the number of parallel approximations to get a more robust result; default = 64 + * @param r the amount of bits that are added to the length of the bitmask to improve the + * accuracy; default = 7 + */ + EffectiveDiameterApproximation(const Graph &G, double ratio = 0.9, count k = 64, count r = 7); + + void run() override; + + /** + * Returns the exact effective diameter of the graph. + * @return the exact effective diameter of the graph + */ + double getEffectiveDiameter() const; + +private: + const Graph *G; + const double ratio; + const count k; + const count r; + double effectiveDiameter; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_EFFECTIVE_DIAMETER_APPROXIMATION_HPP_ diff --git a/vendor/include/networkit/distance/FloydWarshall.hpp b/vendor/include/networkit/distance/FloydWarshall.hpp new file mode 100644 index 0000000..51b695e --- /dev/null +++ b/vendor/include/networkit/distance/FloydWarshall.hpp @@ -0,0 +1,93 @@ +/* FloydWarshall.hpp + * + * Created on: 15.02.2025 + * Authors: Andreas Scharf (andreas.b.scharf@gmail.com) + * + */ + +#ifndef NETWORKIT_DISTANCE_FLOYD_WARSHALL_HPP_ +#define NETWORKIT_DISTANCE_FLOYD_WARSHALL_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @class FloydWarshall + * @brief Computes all-pairs shortest paths using the Floyd-Warshall algorithm. + * + * This algorithm finds the shortest paths between all node pairs in a weighted graph, + * supporting both directed and undirected graphs. It correctly handles negative edge + * weights and detects negative cycles. If multiple shortest paths exist, it returns + * one with the fewest nodes. + * + * The algorithm has a time complexity of O(n³), making it suitable for small to + * medium-sized graphs. + */ +class FloydWarshall : public Algorithm { +public: + /** + * @brief Initializes the Floyd-Warshall algorithm for a given graph. + * + * The input graph must be weighted and may be either directed or undirected. + * + * @param G The graph on which shortest paths will be computed. + */ + FloydWarshall(const Graph &G); + /** + * @brief Runs the Floyd-Warshall algorithm. + * + * Computes shortest path distances and reconstructs paths between all node pairs. + * Also identifies nodes involved in negative cycles. + */ + void run() override; + + /** + * @brief Returns the shortest distance between two nodes. + * + * If no path exists, returns `std::numeric_limits::max()`. + * + * @param source The starting node. + * @param target The destination node. + * @return The shortest path distance from `source` to `target`. + */ + edgeweight getDistance(node source, node target) const; + /** + * @brief Checks whether a node is part of a negative cycle. + * + * A node is considered part of a negative cycle if its shortest path distance + * to itself is negative. + * + * @param u The node to check. + * @return `true` if the node is in a negative cycle, otherwise `false`. + */ + bool isNodeInNegativeCycle(node u) const; + + /** + * @brief Retrieves the shortest path between two nodes. + * + * Returns a sequence of nodes representing the shortest path from `source` to + * `target`. If no path exists, returns an empty vector. + * + * If multiple shortest paths exist with the same total distance, the function + * returns the one with the fewest nodes. + * + * @param source The starting node. + * @param target The destination node. + * @return A vector of nodes forming the shortest path. + */ + std::vector getNodesOnShortestPath(node source, node target) const; + +private: + const Graph *graph; + static constexpr edgeweight infiniteDistance = std::numeric_limits::max(); + std::vector> distances; + std::vector nodesInNegativeCycle; + std::vector> pathMatrix; + std::vector> hops; + void tagNegativeCycles(); +}; +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_FLOYD_WARSHALL_HPP_ diff --git a/vendor/include/networkit/distance/GraphDistance.hpp b/vendor/include/networkit/distance/GraphDistance.hpp new file mode 100644 index 0000000..6e3cafe --- /dev/null +++ b/vendor/include/networkit/distance/GraphDistance.hpp @@ -0,0 +1,49 @@ +/* + * GraphDistance.hpp + * + * Created on: Jul 23, 2013 + * Author: Henning + */ + +#ifndef NETWORKIT_DISTANCE_GRAPH_DISTANCE_HPP_ +#define NETWORKIT_DISTANCE_GRAPH_DISTANCE_HPP_ + +#include +#include +#include + +namespace NetworKit { + +// TODO: inherit from NodeDistance +/** + * @ingroup distance + */ +class GraphDistance final { +public: + /** Default destructor */ + virtual ~GraphDistance() = default; + + /** + * Returns the distance between @a u and @a v in Graph @a g i.e., the length of the shortest + * path between the two. Zero if u = v, maximal possible value if no path exists. + * + * @param g The graph. + * @param u Endpoint of edge. + * @param v Endpoint of edge. + * @return The distance between @a u and @a v. + */ + edgeweight weightedDistance(const Graph &g, node u, node v) const; + + /** + * Returns the number of edges on shortest unweighted path between @a u and @a v in Graph @a g. + * + * @param g The graph. + * @param u Endpoint of edge. + * @param v Endpoint of edge. + * @return The number of edges between @a u and @a v. + */ + count unweightedDistance(const Graph &g, node u, node v) const; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_DISTANCE_GRAPH_DISTANCE_HPP_ diff --git a/vendor/include/networkit/distance/HopPlotApproximation.hpp b/vendor/include/networkit/distance/HopPlotApproximation.hpp new file mode 100644 index 0000000..7493e46 --- /dev/null +++ b/vendor/include/networkit/distance/HopPlotApproximation.hpp @@ -0,0 +1,62 @@ +/* + * HopPlotApproximation.hpp + * + * Created on: 30.03.2016 + * Author: Maximilian Vogel + */ + +#ifndef NETWORKIT_DISTANCE_HOP_PLOT_APPROXIMATION_HPP_ +#define NETWORKIT_DISTANCE_HOP_PLOT_APPROXIMATION_HPP_ + +#include + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + */ +class HopPlotApproximation final : public Algorithm { + +public: + /** + * Computes an approximation of the hop-plot of a given graph + * The hop-plot is the set of pairs (d, g(g)) for each natural number d + * and where g(d) is the fraction of connected node pairs whose shortest connecting path has + * length at most d. Implementation after the ANF algorithm presented in the paper "A Fast and + * Scalable Tool for Data Mining in Massive Graphs"[1] + * + * [1] by Palmer, Gibbons and Faloutsos which can be found here: + * http://www.cs.cmu.edu/~christos/PUBLICATIONS/kdd02-anf.pdf + * + * @param G the given graph + * @param maxDistance the maximum path length that shall be considered. set 0 for + * infinity/diameter of the graph + * @param k the number of parallel approximations to get a more robust result; default = 64 + * @param r the amount of bits that are added to the length of the bitmask to improve the + * accuracy; default = 7 + * @return the approximated hop-plot of the graph + */ + HopPlotApproximation(const Graph &G, count maxDistance = 0, count k = 64, count r = 7); + + void run() override; + + /** + * Returns the approximated hop-plot of the graph. + * @return the approximated hop-plot of the graph + */ + const std::map &getHopPlot() const; + +private: + const Graph *G; + const count maxDistance; + const count k; + const count r; + std::map hopPlot; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_HOP_PLOT_APPROXIMATION_HPP_ diff --git a/vendor/include/networkit/distance/IncompleteDijkstra.hpp b/vendor/include/networkit/distance/IncompleteDijkstra.hpp new file mode 100644 index 0000000..365163a --- /dev/null +++ b/vendor/include/networkit/distance/IncompleteDijkstra.hpp @@ -0,0 +1,66 @@ +/* + * IncompleteDijkstra.hpp + * + * Created on: 15.07.2014 + * Author: dhoske + */ + +#ifndef NETWORKIT_DISTANCE_INCOMPLETE_DIJKSTRA_HPP_ +#define NETWORKIT_DISTANCE_INCOMPLETE_DIJKSTRA_HPP_ + +#include +#include + +#include + +#include +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Implementation of @a IncompleteSSSP using a normal + * Dijkstra with binary heaps. + */ +class IncompleteDijkstra : public IncompleteSSSP { +public: + /** + * Creates a IncompleteDijkstra instance from the sources in + * @a sources (act like a super source) in the graph @a G. + * The edges in @a G must have nonnegative weight and @a G should + * not be null. + * + * We also consider the nodes in @a explored to not exist + * if @a explored is not null. + * + * @warning We do not copy @a G or @a explored, but store a + * non-owning pointer to them. Otherwise IncompleteDijkstra would not + * be more efficient than normal Dijkstra. Thus, @a G and @a explored + * must exist at least as long as this IncompleteDijkstra instance. + * + * @todo This is somewhat ugly, but we do not want introduce a + * std::shared_ptr<> since @a G and @a explored could well + * be stack allocated. + */ + IncompleteDijkstra(const Graph *G, const std::vector &sources, + const std::unordered_set *explored = nullptr); + + bool hasNext() override; + std::pair next() override; + +private: + // Stored reference to outside data structures + const Graph *G; + const std::unordered_set *explored; + + std::vector dists; + + tlx::d_ary_addressable_int_heap> heap; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_INCOMPLETE_DIJKSTRA_HPP_ diff --git a/vendor/include/networkit/distance/IncompleteSSSP.hpp b/vendor/include/networkit/distance/IncompleteSSSP.hpp new file mode 100644 index 0000000..38d877b --- /dev/null +++ b/vendor/include/networkit/distance/IncompleteSSSP.hpp @@ -0,0 +1,41 @@ +/* + * IncompleteSSSP.hpp + * + * Created on: 15.07.2014 + * Author: dhoske + */ + +#ifndef NETWORKIT_DISTANCE_INCOMPLETE_SSSP_HPP_ +#define NETWORKIT_DISTANCE_INCOMPLETE_SSSP_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Abstract base class for single-source shortest path algorithms that return + * the nodes in order of increasing distance from the source and do not + * necessarily need to compute all distances. + */ +class IncompleteSSSP { + +public: + /** + * Returns whether there is a next-nearest node + * or all of the nodes reachable from the source + * have already been processed. + */ + virtual bool hasNext() = 0; + + /** + * Returns the next-nearest node from the source and its + * distance to the source. Should only be called if @a hasNext() + * returns true. + */ + virtual std::pair next() = 0; +}; + +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_INCOMPLETE_SSSP_HPP_ diff --git a/vendor/include/networkit/distance/JaccardDistance.hpp b/vendor/include/networkit/distance/JaccardDistance.hpp new file mode 100644 index 0000000..d759050 --- /dev/null +++ b/vendor/include/networkit/distance/JaccardDistance.hpp @@ -0,0 +1,57 @@ +/* + * JaccardDistance.hpp + * + * Created on: 17.11.2014 + * Author: Michael Hamann, Gerd Lindner + */ + +#ifndef NETWORKIT_DISTANCE_JACCARD_DISTANCE_HPP_ +#define NETWORKIT_DISTANCE_JACCARD_DISTANCE_HPP_ + +#include +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Jaccard distance assigns a distance value to pairs of nodes + * according to the similarity of their neighborhoods. Note that we define the JaccardDistance as + * 1-JaccardSimilarity. + */ +class JaccardDistance final : public NodeDistance { + +public: + /** + * @param G The graph. + * @param triangles Edge attribute containing the number of triangles each edge is contained in. + */ + JaccardDistance(const Graph &G, const std::vector &triangles); + + /** + * REQ: Needs to be called before getEdgeScores delivers meaningful results. + */ + void preprocess() override; + + /** + * Returns the Jaccard distance between node @a u and node @a v. + * @return Jaccard distance between the two nodes. + */ + double distance(node u, node v) override; + + /** + * Returns the Jaccard distances between all connected nodes. + * @return Vector containing the Jaccard distances between all connected pairs of nodes. + */ + const std::vector &getEdgeScores() const override; + +private: + const std::vector &triangles; + std::vector jDistance; // result vector + + inline double getJaccardDistance(count degU, count degV, count t); +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_DISTANCE_JACCARD_DISTANCE_HPP_ diff --git a/vendor/include/networkit/distance/MultiTargetBFS.hpp b/vendor/include/networkit/distance/MultiTargetBFS.hpp new file mode 100644 index 0000000..e66824f --- /dev/null +++ b/vendor/include/networkit/distance/MultiTargetBFS.hpp @@ -0,0 +1,32 @@ +#ifndef NETWORKIT_DISTANCE_MULTI_TARGET_BFS_HPP_ +#define NETWORKIT_DISTANCE_MULTI_TARGET_BFS_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Computes the shortest-path distance from a single source to multiple targets in unweighted + * graphs. + */ +class MultiTargetBFS final : public STSP { + +public: + /** + * Creates the MultiTargetBFS class for a graph @a G, source node @a source, and + * multiple target nodes. + * + * @param G The graph. + * @param source The source node. + * @param targetsFirst,targetsLast Range of target nodes. + */ + template + MultiTargetBFS(const Graph &G, node source, InputIt targetsFirst, InputIt targetsLast) + : STSP(G, source, targetsFirst, targetsLast) {} + + void run() override; +}; +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_MULTI_TARGET_BFS_HPP_ diff --git a/vendor/include/networkit/distance/MultiTargetDijkstra.hpp b/vendor/include/networkit/distance/MultiTargetDijkstra.hpp new file mode 100644 index 0000000..936e9c9 --- /dev/null +++ b/vendor/include/networkit/distance/MultiTargetDijkstra.hpp @@ -0,0 +1,40 @@ +#ifndef NETWORKIT_DISTANCE_MULTI_TARGET_DIJKSTRA_HPP_ +#define NETWORKIT_DISTANCE_MULTI_TARGET_DIJKSTRA_HPP_ + +#include +#include + +#include + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Computes the shortest-path distance from a single source to multiple targets in weighted graphs. + */ +class MultiTargetDijkstra final : public STSP { + +public: + /** + * Creates the MultiTargetDijkstra class for a graph @a G, source node @a source, and + * multiple target nodes. + * + * @param G The graph. + * @param source The source node. + * @param targetsFirst,targetsLast Range of target nodes. + */ + template + MultiTargetDijkstra(const Graph &G, node source, InputIt targetsFirst, InputIt targetsLast) + : STSP(G, source, targetsFirst, targetsLast) {} + + void run() override; + +private: + std::vector distFromSource; + tlx::d_ary_addressable_int_heap> heap{distFromSource}; +}; +} // namespace NetworKit + +#endif // NETWORKIT_DISTANCE_MULTI_TARGET_DIJKSTRA_HPP_ diff --git a/vendor/include/networkit/distance/NeighborhoodFunction.hpp b/vendor/include/networkit/distance/NeighborhoodFunction.hpp new file mode 100644 index 0000000..77866d5 --- /dev/null +++ b/vendor/include/networkit/distance/NeighborhoodFunction.hpp @@ -0,0 +1,47 @@ +/* + * NeighborhoodFunction.hpp + * + * Created on: 30.03.2016 + * Author: Maximilian Vogel + */ + +#ifndef NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_HPP_ +#define NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + */ +class NeighborhoodFunction final : public Algorithm { + +public: + /** + * Computes the neighborhood function exactly. + * The neighborhood function N of a graph G for a given distance t is defined + * as the number of node pairs (u,v) that can be reached within distance t. + * + * @param G the given graph + * @return the exact effective diameter of the graph + */ + NeighborhoodFunction(const Graph &G); + + void run() override; + + /** + * Returns the neighborhood function of the graph. + * @return the neighborhood function of the graph + */ + const std::vector &getNeighborhoodFunction() const; + +private: + const Graph *G; + std::vector result; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_HPP_ diff --git a/vendor/include/networkit/distance/NeighborhoodFunctionApproximation.hpp b/vendor/include/networkit/distance/NeighborhoodFunctionApproximation.hpp new file mode 100644 index 0000000..379c22f --- /dev/null +++ b/vendor/include/networkit/distance/NeighborhoodFunctionApproximation.hpp @@ -0,0 +1,56 @@ +/* + * NeighborhoodFunctionApproximation.hpp + * + * Created on: 30.03.2016 + * Author: Maximilian Vogel + */ + +#ifndef NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_APPROXIMATION_HPP_ +#define NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_APPROXIMATION_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + */ +class NeighborhoodFunctionApproximation final : public Algorithm { + +public: + /** + * Computes an approximation of the neighborhood function. + * The neighborhood function N of a graph G for a given distance t is defined + * as the number of node pairs (u,v) that can be reached within distance t. + * Implementation after the ANF algorithm presented in the paper "A Fast and Scalable Tool for + * Data Mining in Massive Graphs"[1] + * + * [1] by Palmer, Gibbons and Faloutsos which can be found here: + * http://www.cs.cmu.edu/~christos/PUBLICATIONS/kdd02-anf.pdf + * + * @param G the given graph + * @param k the number of parallel approximations to get a more robust result; default = 64 + * @param r the amount of bits that are added to the length of the bitmask to improve the + * accuracy; default = 7 + */ + NeighborhoodFunctionApproximation(const Graph &G, count k = 64, count r = 7); + + void run() override; + + /** + * Returns the approximated neighborhood function of the graph. + * @return the approximated neighborhood function of the graph + */ + const std::vector &getNeighborhoodFunction() const; + +private: + const Graph *G; + const count k; + const count r; + std::vector result; +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_APPROXIMATION_HPP_ diff --git a/vendor/include/networkit/distance/NeighborhoodFunctionHeuristic.hpp b/vendor/include/networkit/distance/NeighborhoodFunctionHeuristic.hpp new file mode 100644 index 0000000..fe2ad63 --- /dev/null +++ b/vendor/include/networkit/distance/NeighborhoodFunctionHeuristic.hpp @@ -0,0 +1,56 @@ +/* + * NeighborhoodFunctionHeuristic.hpp + * + * Author: Maximilian Vogel + */ + +#ifndef NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_HEURISTIC_HPP_ +#define NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_HEURISTIC_HPP_ + +#include +#include + +namespace NetworKit { + +/** + * @ingroup distance + */ +class NeighborhoodFunctionHeuristic final : public Algorithm { + +public: + enum SelectionStrategy { RANDOM, SPLIT }; + /** + * Computes a heuristic of the neighborhood function. + * + * The algorithm runs nSamples breadth-first searches and scales the results up to the actual + * amount of nodes. Accepted strategies are "split" and "random". + * + * @param G the given graph + * @param nSamples the amount of samples, set to zero for heuristic of max(sqrt(m), 0.15*n) + * @param strategy the strategy to select the samples, accepts "random" or "split" + */ + NeighborhoodFunctionHeuristic(const Graph &G, count nSamples = 0, + SelectionStrategy strategy = SPLIT); + + void run() override; + + /** + * Returns the approximated neighborhood function of the graph. + * @return the approximated neighborhood function of the graph + */ + const std::vector &getNeighborhoodFunction() const; + +private: + const Graph *G; + const count nSamples; + const SelectionStrategy strategy; + std::vector result; + + /* selection schemes implemented as private functions */ + std::vector random(const Graph &G, count nSamples); + std::vector split(const Graph &G, count nSamples); +}; + +} /* namespace NetworKit */ + +#endif // NETWORKIT_DISTANCE_NEIGHBORHOOD_FUNCTION_HEURISTIC_HPP_ diff --git a/vendor/include/networkit/distance/NodeDistance.hpp b/vendor/include/networkit/distance/NodeDistance.hpp new file mode 100644 index 0000000..9aad8b5 --- /dev/null +++ b/vendor/include/networkit/distance/NodeDistance.hpp @@ -0,0 +1,54 @@ +/* + * NodeDistance.hpp + * + * Created on: 18.06.2013 + * Author: cls + */ + +#ifndef NETWORKIT_DISTANCE_NODE_DISTANCE_HPP_ +#define NETWORKIT_DISTANCE_NODE_DISTANCE_HPP_ + +#include + +namespace NetworKit { + +/** + * @ingroup distance + * Abstract base class for node distance measures. + */ +class NodeDistance { + +protected: + const Graph *G; + +public: + /** + * Constructs the NodeDistance class for the given Graph @a G. + * + * @param G The graph. + */ + NodeDistance(const Graph &G) : G(&G) {} + + /** Default destructor */ + virtual ~NodeDistance() = default; + + /** + * Perform preprocessing work. Needs to be called before distances are requested. + */ + virtual void preprocess() = 0; + + /** + * Return the distance between two nodes. + * The distance must be normed to return a distance between 0 and 1. + */ + virtual double distance(node u, node v) = 0; + + /** + * Returns the distances between all connected pairs of nodes. + * @return Vector containing the distances between all connected pairs of nodes. + */ + virtual const std::vector &getEdgeScores() const = 0; +}; + +} /* namespace NetworKit */ +#endif // NETWORKIT_DISTANCE_NODE_DISTANCE_HPP_ diff --git a/vendor/include/networkit/distance/PrunedLandmarkLabeling.hpp b/vendor/include/networkit/distance/PrunedLandmarkLabeling.hpp new file mode 100644 index 0000000..7f7793e --- /dev/null +++ b/vendor/include/networkit/distance/PrunedLandmarkLabeling.hpp @@ -0,0 +1,76 @@ +#ifndef NETWORKIT_DISTANCE_PRUNED_LANDMARK_LABELING_HPP_ +#define NETWORKIT_DISTANCE_PRUNED_LANDMARK_LABELING_HPP_ + +#include +#include + +#include +#include + +namespace NetworKit { + +class PrunedLandmarkLabeling : public Algorithm { + +public: + /** + * Pruned Landmark Labeling algorithm based on the paper "Fast exact shortest-path distance + * queries on large networks by pruned landmark labeling" from Akiba et al., ACM SIGMOD 2013. + * The algorithm computes distance labels by performing pruned breadth-first searches from each + * vertex. Labels are used to quickly retrieve shortest-path distances between node pairs. + * @note this algorithm only works for unweighted graphs. + * + * @param G The input graph. + */ + PrunedLandmarkLabeling(const Graph &G); + + /** + * Computes distance labels. Run this function before calling 'query'. + */ + void run() override; + + /** + * Returns the shortest-path distance between the two nodes. + * + * @param u Source node. + * @param v Target node. + * + * @return The shortest-path distance from @a u to @a v. + */ + count query(node u, node v) const; + +protected: + count queryImpl(node u, node v, node upperBound = none) const; + + static constexpr count infDist = std::numeric_limits::max(); + + struct Label { + Label() : node_(none), distance_(infDist) {} + Label(node node_, count distance_) : node_(node_), distance_(distance_) {} + node node_; + count distance_; + }; + + const Graph *G; + std::vector nodesSortedByDegreeDesc; + std::vector visited; + std::vector> labelsOut, labelsIn; + std::vector