From 8e21dffd1354a36658f87b51116c399f267052c0 Mon Sep 17 00:00:00 2001 From: carlos_felix Date: Sun, 22 Oct 2023 22:22:52 +0100 Subject: [PATCH 1/2] network dynamics matrices --- include/CXXGraph/Graph/Graph.hpp | 127 ++++++++++++++++++++++++++- include/CXXGraph/Utility/Typedef.hpp | 18 ++++ 2 files changed, 144 insertions(+), 1 deletion(-) diff --git a/include/CXXGraph/Graph/Graph.hpp b/include/CXXGraph/Graph/Graph.hpp index 166766bc3..2312fa5ae 100644 --- a/include/CXXGraph/Graph/Graph.hpp +++ b/include/CXXGraph/Graph/Graph.hpp @@ -106,7 +106,9 @@ class Graph { T_NodeSet isolatedNodesSet = {}; shared> cachedAdjMatrix; - + shared> cachedDegreeMatrix; + shared> cachedLaplacianMatrix; + shared> cachedTransitionMatrix; // Private non-const getter for the set of nodes std::unordered_set>, nodeHash> nodeSet(); @@ -304,6 +306,33 @@ class Graph { virtual shared> getAdjMatrix() const; virtual void cacheAdjMatrix(); + /** + * @brief This function generates a list of the degree matrix with every element + * of the matrix containing the node where the link is directed and the + * corresponding edge to the link. + * Note: No Thread Safe + */ + virtual shared> getDegreeMatrix() const; + + virtual void cacheDegreeMatrix(); + /** + * @brief This function generates a list of the Laplacian matrix with every element + * of the matrix containing the node connected to the current node and the + * corresponding edge to the link. + * Note: No Thread Safe + */ + virtual shared> getLaplacianMatrix() const; + + virtual void cacheLaplacianMatrix(); + /** + * @brief This function generates a list of the transition matrix with every element + * of the matrix containing the node that can be transitioned to from the + * current node and the probability of the transition. + * Note: No Thread Safe + */ + virtual shared> getTransitionMatrix() const; + + virtual void cacheTransitionMatrix(); /** * \brief This function generates a set of nodes linked to the provided node * in a directed graph @@ -831,6 +860,9 @@ template Graph::Graph() { /* Caching the adjacency matrix */ cacheAdjMatrix(); + cacheDegreeMatrix(); + cacheLaplacianMatrix(); + cacheTransitionMatrix(); } template @@ -840,6 +872,9 @@ Graph::Graph(const T_EdgeSet &edgeSet) { } /* Caching the adjacency matrix */ cacheAdjMatrix(); + cacheDegreeMatrix(); + cacheLaplacianMatrix(); + cacheTransitionMatrix(); } template @@ -855,6 +890,8 @@ void Graph::setEdgeSet(const T_EdgeSet &edgeSet) { } /* Caching the adjacency matrix */ cacheAdjMatrix(); + cacheDegreeMatrix(); + cacheLaplacianMatrix(); } template @@ -1666,6 +1703,94 @@ void Graph::cacheAdjMatrix() { this->cachedAdjMatrix = adj; } +template +shared> Graph::getDegreeMatrix() const { + auto degreeMatrix = std::make_shared>(); + + for (const auto& nodePair : *this->cachedAdjMatrix) { + const shared>& node = nodePair.first; + const std::vector>, shared>>>& neighbors = nodePair.second; + + int degree = neighbors.size(); + + (*degreeMatrix)[node] = {degree}; + } + + return degreeMatrix; +} + +template +void Graph::cacheDegreeMatrix() { + const auto degreeMatrix = Graph::getDegreeMatrix(); + this->cachedDegreeMatrix = degreeMatrix; +} + +template +shared> Graph::getLaplacianMatrix() const { + const auto adjacencyMatrix = this->cachedAdjMatrix; + const auto degreeMatrix = this->cachedDegreeMatrix; + + auto laplacianMatrix = std::make_shared>(); + for (const auto& nodePair : *adjacencyMatrix) { + const shared>& node = nodePair.first; + (*laplacianMatrix)[node] = std::vector>, shared>>>(); + } + + for (const auto& nodePair : *adjacencyMatrix) { + const shared>& node = nodePair.first; + const std::vector>, shared>>>& neighbors = nodePair.second; + + int degree = neighbors.size(); + + (*laplacianMatrix)[node].emplace_back(node, nullptr); // Insere o nó na diagonal + for (const auto& neighborPair : neighbors) { + const shared>& neighbor = neighborPair.first; + (*laplacianMatrix)[node].emplace_back(neighbor, neighborPair.second); // Insere os pares de vizinhos + } + } + + return laplacianMatrix; +} + +template +void Graph::cacheLaplacianMatrix() { + const auto laplacianMatrix = Graph::getLaplacianMatrix(); + this->cachedLaplacianMatrix = laplacianMatrix; +} + +template +shared> Graph::getTransitionMatrix() const { + const auto adjacencyMatrix = this->cachedAdjMatrix; + + auto transitionMatrix = std::make_shared>(); + for (const auto& nodePair : *adjacencyMatrix) { + const shared>& node = nodePair.first; + (*transitionMatrix)[node] = std::vector>, double>>(); + } + + for (const auto& nodePair : *adjacencyMatrix) { + const shared>& node = nodePair.first; + const std::vector>, shared>>>& neighbors = nodePair.second; + + int degree = neighbors.size(); + + double transitionProbability = 1.0 / degree; + + for (const auto& neighborPair : neighbors) { + const shared>& neighbor = neighborPair.first; + (*transitionMatrix)[node].emplace_back(neighbor, transitionProbability); + } + } + + return transitionMatrix; +} + +template +void Graph::cacheTransitionMatrix() { + const auto transitionMatrix = Graph::getTransitionMatrix(); + this->cachedTransitionMatrix = transitionMatrix; +} + template const std::unordered_set>, nodeHash> Graph::outNeighbors(const Node *node) const { diff --git a/include/CXXGraph/Utility/Typedef.hpp b/include/CXXGraph/Utility/Typedef.hpp index 108101e40..7915a4457 100755 --- a/include/CXXGraph/Utility/Typedef.hpp +++ b/include/CXXGraph/Utility/Typedef.hpp @@ -254,6 +254,24 @@ using AdjacencyMatrix = std::unordered_map< std::vector>, shared>>>, nodeHash>; +template +using DegreeMatrix = std::unordered_map< + shared>, + std::vector, + nodeHash>; + +template +using LaplacianMatrix = std::unordered_map< + shared>, + std::vector>, shared>>>, + nodeHash>; + +template +using TransitionMatrix = std::unordered_map< + shared>, + std::vector>, double>>, + nodeHash>; + template using PartitionMap = std::unordered_map Date: Mon, 23 Oct 2023 22:55:29 +0100 Subject: [PATCH 2/2] added example and readme update --- README.md | 14 +++++ examples/CMakeLists.txt | 1 + .../NetworkDynamicsExample/CMakeLists.txt | 17 +++++ .../network_dynamics_example.cpp | 62 +++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 examples/NetworkDynamicsExample/CMakeLists.txt create mode 100644 examples/NetworkDynamicsExample/network_dynamics_example.cpp diff --git a/README.md b/README.md index 8eb288ef1..cf0c21d25 100755 --- a/README.md +++ b/README.md @@ -573,6 +573,20 @@ Eva(u,v)(i) =I(u ∈ keep[i]) + I(v ∈ keep[i]) +α * \frac{ecount[i]}{(|E|/p)} The lowest value is taken as partition Id. +## Network Dynamics + +### Degree Matrix + +The Degree Matrix is a square matrix that provides insights into the connectivity of nodes in a graph. For directed graphs, it reflects the number of incoming and outgoing edges for each node, while for undirected graphs, it represents the number of edges incident to each node. + +### Laplacian Matrix + +The Laplacian Matrix is a square matrix derived from the adjacency matrix and degree matrix of a graph. It is instrumental in analyzing various properties of the graph, such as connectedness, the count of spanning trees, and other spectral characteristics. + +### Transition Matrix + +The Transition Matrix is commonly used in the study of Markov Chains and stochastic processes. Within the context of a graph, it denotes the probabilities of transitioning from one node to another, often based on the edge weights or predetermined criteria. This matrix finds applications in various fields such as network analysis, machine learning, and optimization. + ## How to contribute [![GitHub contributors](https://img.shields.io/github/contributors/ZigRazor/CXXGraph.svg)](https://GitHub.com/ZigRazor/CXXGraph/graphs/contributors/) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0745f795e..7b3cbc33d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,6 +3,7 @@ if(EXAMPLES) add_subdirectory(DialExample) add_subdirectory(DijkstraExample) +add_subdirectory(NetworkDynamicsExample) add_subdirectory(PartitionExample) endif(EXAMPLES) \ No newline at end of file diff --git a/examples/NetworkDynamicsExample/CMakeLists.txt b/examples/NetworkDynamicsExample/CMakeLists.txt new file mode 100644 index 000000000..f1b942ddd --- /dev/null +++ b/examples/NetworkDynamicsExample/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.9) +project(NetworkDynamicsExample) + +# specify the C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES /usr/local/lib ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}) + +add_executable(network_dynamics_example network_dynamics_example.cpp) +target_include_directories(network_dynamics_example PUBLIC "${CMAKE_SOURCE_DIR}/include") + +target_link_libraries(network_dynamics_example + pthread + ssl + crypto + z) \ No newline at end of file diff --git a/examples/NetworkDynamicsExample/network_dynamics_example.cpp b/examples/NetworkDynamicsExample/network_dynamics_example.cpp new file mode 100644 index 000000000..522e11df9 --- /dev/null +++ b/examples/NetworkDynamicsExample/network_dynamics_example.cpp @@ -0,0 +1,62 @@ +#include "CXXGraph/CXXGraph.hpp" + +#include + +using std::make_shared; + +int main() { + CXXGraph::Node node0("0", 0); + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + + CXXGraph::UndirectedWeightedEdge edge1(1, node1, node2, 2.0); + CXXGraph::UndirectedWeightedEdge edge2(2, node2, node3, 2.0); + CXXGraph::UndirectedWeightedEdge edge3(3, node0, node1, 2.0); + CXXGraph::UndirectedWeightedEdge edge4(4, node0, node3, 1.0); + + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + edgeSet.insert(make_shared>(edge4)); + + CXXGraph::Graph graph(edgeSet); + + auto degreeMatrix = graph.getDegreeMatrix(); + for (const auto& nodePair : *degreeMatrix) { + const CXXGraph::shared>& node = nodePair.first; + const std::vector& degrees = nodePair.second; + + std::cout << "Node: " << node->getId() << ", Degree: " << degrees[0] << "\n"; + } + auto laplacianMatrix = graph.getLaplacianMatrix(); + for (const auto& nodePair : *laplacianMatrix) { + const auto& node = nodePair.first; + const auto& neighbors = nodePair.second; + + std::cout << "Node " << node->getId() << " connected to:" << std::endl; + for (const auto& neighbor : neighbors) { + if (neighbor.first == node) { + std::cout << " -> Itself" << std::endl; + } else { + std::cout << " -> Node " << neighbor.first->getId() << " with Edge ID " << (neighbor.second ? neighbor.second->getId() : -1) << std::endl; + } + } + std::cout << std::endl; + } + + auto transitionMatrix = graph.getTransitionMatrix(); + for (const auto& nodePair : *transitionMatrix) { + const auto& node = nodePair.first; + const auto& transitions = nodePair.second; + + std::cout << "Transitions from Node " << node->getId() << ":" << std::endl; + for (const auto& transition : transitions) { + std::cout << " -> To Node " << transition.first->getId() << " with Probability " << transition.second << std::endl; + } + std::cout << std::endl; + } + + return 0; +}