From 516f6c22fb06b623eae3d1bf318a1a5f5615279c Mon Sep 17 00:00:00 2001 From: Paul Nitzke <14367-paulenit@users.noreply.git.rwth-aachen.de> Date: Sat, 9 Jul 2022 20:07:14 +0200 Subject: [PATCH] Fix: Change backing datastructure of graphs * Replaces List with Dictionary with the node index being the key and the GraphNode (also containing the index) the value * This dramatically speeds up the MatrixMarket string to graph transformation in MatrixMarketReader since adding edges and in particular nodes to the graph is much faster * This is because the nodes are added to the graph as needes i.e. the graph searches for them in the existing node list and if not present adds them. This search is significant the larger the graph gets. This is also why the transformation of larger graphs took exponentially longer. --- .../DataStructures/AdjacencyGraph.cs | 32 +++---- .../DataStructures/BipartiteGraph.cs | 84 ++++++------------- 2 files changed, 36 insertions(+), 80 deletions(-) diff --git a/src/SparseTransform/DataStructures/AdjacencyGraph.cs b/src/SparseTransform/DataStructures/AdjacencyGraph.cs index 3adba2e..2693bdb 100644 --- a/src/SparseTransform/DataStructures/AdjacencyGraph.cs +++ b/src/SparseTransform/DataStructures/AdjacencyGraph.cs @@ -11,7 +11,7 @@ namespace SparseTransform.DataStructures /// <remarks> /// In the matrix representation this is the lower left triangle since <see cref="AdjacencyGraph"/> represents symmetric matrices. /// </remarks> - private List<GraphNode> _nodes; + private Dictionary<int, GraphNode> _nodes; /// <summary> /// Number of nodes @@ -58,7 +58,7 @@ namespace SparseTransform.DataStructures List<int> colors = new List<int>(); if (Colored) { - foreach (GraphNode node in _nodes) + foreach (GraphNode node in _nodes.Values) { int color = node.Color; // Do not check for != 0 since we already know everything here is colored @@ -79,7 +79,7 @@ namespace SparseTransform.DataStructures /// </summary> public AdjacencyGraph() { - _nodes = new List<GraphNode>(); + _nodes = new Dictionary<int, GraphNode>(); } public void AddEdge(int i, int j) @@ -106,14 +106,16 @@ namespace SparseTransform.DataStructures /// <returns>GraphNode that was just added</returns> private GraphNode AddNode(int index) { - GraphNode? n = FindNodeByIndex(index); - if (n is null) + if(!_nodes.ContainsKey(index)) { - n = new GraphNode(index); - _nodes.Add(n); + GraphNode n = new GraphNode(index); + _nodes[index] = n; return n; } - return n; + else + { + return _nodes[index]; + } } /// <summary> @@ -122,7 +124,7 @@ namespace SparseTransform.DataStructures /// <returns>IEnumerable for the nodes</returns> public IEnumerable<GraphNode> GetNodes() { - List<GraphNode> nodes = new List<GraphNode>(_nodes); + List<GraphNode> nodes = new List<GraphNode>(_nodes.Values); nodes.Sort((x, y) => { if (x.Index < y.Index) @@ -133,23 +135,13 @@ namespace SparseTransform.DataStructures return nodes as IEnumerable<GraphNode>; } - /// <summary> - /// Finds a node by index. Returns null if not found. - /// </summary> - /// <param name="index">index to search for</param> - /// <returns>node if found otherwise null</returns> - private GraphNode? FindNodeByIndex(int index) - { - return _nodes.Find(n => n.Index == index); - } - public IntegerMatrix? ToSeedMatrix(int rows) { IntegerMatrix seed = new IntegerMatrix(rows, ColorsUsed); // This only works for row OR column partitions not mixed if (Colored) { - foreach (GraphNode node in _nodes) + foreach (GraphNode node in _nodes.Values) { // The row index is the column index of the element // The column index = binary vector index is the color diff --git a/src/SparseTransform/DataStructures/BipartiteGraph.cs b/src/SparseTransform/DataStructures/BipartiteGraph.cs index 6c9b542..dab7578 100644 --- a/src/SparseTransform/DataStructures/BipartiteGraph.cs +++ b/src/SparseTransform/DataStructures/BipartiteGraph.cs @@ -14,7 +14,7 @@ namespace SparseTransform.DataStructures /// <remarks> /// Uses "left" in the name since ColPack does it too and in visualizations this is where the row nodes are often pictured. /// </remarks> - private List<GraphNode> _leftNodes; + private Dictionary<int, GraphNode> _leftNodes; /// <summary> /// Stores nodes representing columns in the matrix representation. @@ -22,7 +22,7 @@ namespace SparseTransform.DataStructures /// <remarks> /// Uses "right" in the name since ColPack does this too and in visualizations this is where the row nodes are often pictured. /// </remarks> - private List<GraphNode> _rightNodes; + private Dictionary<int, GraphNode> _rightNodes; /// <summary> /// Number of nodes on the left side @@ -101,7 +101,7 @@ namespace SparseTransform.DataStructures List<int> colors = new List<int>(); if (LeftColored) { - foreach (GraphNode node in _leftNodes) + foreach (GraphNode node in _leftNodes.Values) { int color = node.Color; // Do not check for != 0 since we already know everything here is colored @@ -113,7 +113,7 @@ namespace SparseTransform.DataStructures } if (RightColored) { - foreach (GraphNode node in _rightNodes) + foreach (GraphNode node in _rightNodes.Values) { int color = node.Color; // Do not check for != 0 since we already know everything here is colored @@ -136,8 +136,8 @@ namespace SparseTransform.DataStructures /// </summary> public BipartiteGraph() { - _leftNodes = new List<GraphNode>(); - _rightNodes = new List<GraphNode>(); + _leftNodes = new Dictionary<int, GraphNode>(); + _rightNodes = new Dictionary<int, GraphNode>(); } /// <summary> @@ -165,14 +165,16 @@ namespace SparseTransform.DataStructures /// <param name="index">index to create node for</param> private GraphNode AddLeftNode(int index) { - GraphNode? n = FindLeftNodeByIndex(index); - if (n is null) + if(!_leftNodes.ContainsKey(index)) { - n = new GraphNode(index); - _leftNodes.Add(n); + GraphNode n = new GraphNode(index); + _leftNodes[index] = n; return n; } - return n; + else + { + return _leftNodes[index]; + } } /// <summary> @@ -181,54 +183,16 @@ namespace SparseTransform.DataStructures /// <param name="index">index to create node for</param> private GraphNode AddRightNode(int index) { - GraphNode? n = FindRightNodeByIndex(index); - if (n is null) + if(!_rightNodes.ContainsKey(index)) { - n = new GraphNode(index); - _rightNodes.Add(n); + GraphNode n = new GraphNode(index); + _rightNodes[index] = n; return n; } - return n; - } - - /// <summary> - /// Checks if node exists on the left side - /// </summary> - /// <param name="index">index to check for</param> - /// <returns>true if node was found</returns> - private bool ContainsLeftNode(int index) - { - return FindLeftNodeByIndex(index) is GraphNode; - } - - /// <summary> - /// Checks if node exists on the right side - /// </summary> - /// <param name="index">index to check for</param> - /// <returns>true if node was found</returns> - private bool ContainsRightNode(int index) - { - return FindRightNodeByIndex(index) is GraphNode; - } - - /// <summary> - /// Finds a node on the left side by index. Returns null if not found. - /// </summary> - /// <param name="index">index to search for</param> - /// <returns>GraphNode if found, null if not</returns> - private GraphNode? FindLeftNodeByIndex(int index) - { - return _leftNodes.Find(n => n.Index == index); - } - - /// <summary> - /// Finds a node on the right side by index. Returns null if not found. - /// </summary> - /// <param name="index">index to search for</param> - /// <returns>GraphNode if found, null if not</returns> - private GraphNode? FindRightNodeByIndex(int index) - { - return _rightNodes.Find(n => n.Index == index); + else + { + return _rightNodes[index]; + } } /// <summary> @@ -237,7 +201,7 @@ namespace SparseTransform.DataStructures /// <returns>IEnumerable for the left nodes</returns> public IEnumerable<GraphNode> GetLeftNodes() { - List<GraphNode> leftNodes = new List<GraphNode>(_leftNodes); + List<GraphNode> leftNodes = new List<GraphNode>(_leftNodes.Values); leftNodes.Sort((x, y) => { if (x.Index < y.Index) @@ -254,7 +218,7 @@ namespace SparseTransform.DataStructures /// <returns>IEnumerable for the right nodes</returns> public IEnumerable<GraphNode> GetRightNodes() { - List<GraphNode> rightNodes = new List<GraphNode>(_rightNodes); + List<GraphNode> rightNodes = new List<GraphNode>(_rightNodes.Values); rightNodes.Sort((x, y) => { if (x.Index < y.Index) @@ -277,7 +241,7 @@ namespace SparseTransform.DataStructures // This only works for row OR column partitions not mixed if (LeftColored) { - foreach (GraphNode node in _leftNodes) + foreach (GraphNode node in _leftNodes.Values) { // The row index is the column index of the element // The column index = binary vector index is the color @@ -288,7 +252,7 @@ namespace SparseTransform.DataStructures } else if (RightColored) { - foreach (GraphNode node in _rightNodes) + foreach (GraphNode node in _rightNodes.Values) { // The row index is the row index of the element seed[node.Index - 1, node.Color - 1] = 1; -- GitLab