diff --git a/README.md b/README.md index 0562f7c96..8eb288ef1 100755 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ Share on [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Header-Only%20C++%20Library%20for%20Graph%20Representation%20and%20Algorithms%204&url=https://github.com/ZigRazor/CXXGraph&hashtags=cpp,headeronly,library,opensource,developers)

+ ## Introduction -**CXXGraph** is a small library, header only, that manages the Graph and it's algorithms in **C++**. In other words a "Comprehensive C++ Graph Library". -An alternative to [Boost Graph Library (BGL)](https://www.boost.org/doc/libs/1_77_0/libs/graph/doc/index.html). +**CXXGraph** is a comprehensive C++ library that manages graph algorithms. This header-only library serves as an alternative to the [Boost Graph Library (BGL)](https://www.boost.org/doc/libs/1_77_0/libs/graph/doc/index.html). ## Warning ⚠️ @@ -49,8 +49,8 @@ Happy Coding!! 😄 **We are looking for:** -- **Site Developer** for the development of the CXXGraph site ( for the moment on GitHub Page ); -- **Developers and Committers**, also at *first experience*, we will guide you step by step to the open-source world! +- **A Web Developer** for the development of the CXXGraph website. All documentation is currently hosted on this GitHub page. +- **Developers and Contributors** to provide input. If you are new to the open-source world, we will guide you step by step! If you are interested, please contact us at zigrazor@gmail.com or contribute to this project. We are waiting for you! @@ -173,149 +173,150 @@ If you are interested, please contact us at zigrazor@gmail.com or contribute to ### Install Linux Tarballs -On Unix/Linux system you need to execute the following command to install: +To install on Unix/Linux systems, execute the following from the command line: `$ sudo tar xjf CXXGraph-{version}.tar.bz2` -to uninstall: +To uninstall: `$ sudo rm -f /usr/include/Graph.hpp /usr/include/CXXGraph*` ### Install RPM -On Fedora/CentOS/RedHat system you need to execute the following command to install: +To install on Fedora/CentOS/RedHat systems, execute the following from the command line: `$ sudo rpm -ivh CXXGraph-{version}.noarch.rpm` -to uninstall: +To uninstall: `$ sudo rpm -e CXXGraph-{version}` ### Install DEB -On Debian/Ubuntu system you need to execute the following command to install: +To install on Debian/Ubuntu systems, execute the following from the command line: `$ sudo dpkg -i CXXGraph_{version}.deb` -to uninstall: +To uninstall: `$ sudo apt-get remove CXXGraph` ### Install From Source -You can install from source the library using CMake. After the compilation phase, you can use: +For self-compiled installations using CMake, execute the following from the command line once compilation is complete: `$ sudo make install` -to install the library. - ## Classes Explanation -The Classes Explanation can be found in the [Doxygen Documentation](https://rawcdn.githack.com/ZigRazor/CXXGraph/master/docs/html/index.html), in the [Classes Section](https://rawcdn.githack.com/ZigRazor/CXXGraph/master/docs/html/classes.html) +The Classes Explanation can be found in the [Classes Section](https://rawcdn.githack.com/ZigRazor/CXXGraph/master/docs/html/classes.html) of the [Doxygen Documentation](https://rawcdn.githack.com/ZigRazor/CXXGraph/master/docs/html/index.html) -## Requirements +## Prerequisites -- The minimum C++ standard required is **C++17** -- A GCC compiler version greater than 7.3.0 *OR* -- A MSVC compiler that supports C++17 +- The minimum C++ standard required is **C++17** +- A GCC compiler version 7.3.0 and later *OR* a MSVC compiler that supports C++17 ## How to use -The use of the library is very simple, **just put the header file where you need!** +To use the library **simply put the header file where you need it.** It's that easy! ## Example -Work in Progess +Work in Progress ## Unit-Test Execution -The Unit-Test required the CMake version greater than 3.9 and the **google test** library. +The Unit-Test requires CMake 3.9 and later, and the **[GoogleTest](https://github.com/google/googletest)** library. -### Google Test Installation +### Install GoogleTest [GoogleTest](https://github.com/google/googletest) ```bash git clone https://github.com/google/googletest.git -cd googletest # Main directory of the cloned repository. -mkdir -p build # Create a directory to hold the build output. +cd googletest # Main directory of the cloned repository +mkdir -p build # Create a directory to hold the build output cd build -cmake .. # Generate native build scripts for GoogleTest. +cmake .. # Generate native build scripts for GoogleTest make # Compile sudo make install # Install in /usr/local/ by default ``` -### How to Compile Test +### How to Compile GoogleTest From the base directory: ```bash -mkdir -p build # Create a directory to hold the build output. +mkdir -p build # Create a directory to hold the build output cd build # Enter the build folder -cmake .. # Generate native build scripts for GoogleTest. +cmake .. # Generate native build scripts for GoogleTest make # Compile ``` -### How to Run Test +### How to Run GoogleTest -After the compilation, you can run the executable that is under the "build" directory with the name "test_exe", with the simple command `./test_exe`. +After the build has compiled, run the "test_exe" executable in the "build" directory with the following command: + +`./test_exe` ## Benchmark Execution -The Benchmark required the CMake version greater than 3.9 and the **google test** and the **google benchmark** library. +The Benchmark requires CMake 3.9 and later, the **GoogleTest** library, and the **Google Benchmark** library. -### Google Benchmark Installation +### Install Google Benchmark [Google Benchmark](https://github.com/google/benchmark) ```bash -# Check out the library. +# Check out the library $ git clone https://github.com/google/benchmark.git -# Benchmark requires Google Test as a dependency. Add the source tree as a subdirectory. +# Google Benchmark requires GoogleTest as a dependency. Add the source tree as a subdirectory $ git clone https://github.com/google/googletest.git benchmark/googletest -# Go to the library root directory +# Go to the library's root directory $ cd benchmark -# Make a build directory to place the build output. +# Make a build directory to place the build output $ cmake -E make_directory "build" -# Generate build system files with cmake. +# Generate the build system files with CMake $ cmake -E chdir "build" cmake -DCMAKE_BUILD_TYPE=Release ../ -# or, starting with CMake 3.13, use a simpler form: +# If starting with CMake 3.13, you can use the following: # cmake -DCMAKE_BUILD_TYPE=Release -S . -B "build" -# Build the library. +# Build the library $ cmake --build "build" --config Release -# install library +# Install the library $ sudo cmake --build "build" --config Release --target install ``` -### How to Compile Benchmark +### How to Compile Google Benchmark From the base directory: ```bash -mkdir -p build # Create a directory to hold the build output. +mkdir -p build # Create a directory to hold the build output cd build # Enter the build folder -cmake -DBENCHMARK=ON .. # Generate native build scripts for GoogleTest. +cmake -DBENCHMARK=ON .. # Generate native build scripts for GoogleTest make # Compile ``` -### How to Run Benchmark +### How to Run Google Benchmark + +After the build has compiled, run the "benchmark" executable in the "build" directory with the following command: -After the compilation, you can run the executable that is under the "build" directory with the name "benchmark", with the simple command `./benchmark`. +`./benchmark` ### Benchmark Results -You can check benchmark result at this [link](https://zigrazor.github.io/CXXGraph/dev/bench/) +You can check the benchmark result using this [link](https://zigrazor.github.io/CXXGraph/dev/bench/). ## Packaging ### Tarballs -To create tarballs package you need to follow the following steps: +To create a tarball package, execute the following from the command line: ```bash # Enter Packaging Directory $ cd packaging -# execute the script to generate tarballs +# Execute the script to generate tarballs $ ./tarballs.sh ``` @@ -323,12 +324,12 @@ $ ./tarballs.sh #### (Fedora/CentOS/RedHat) -To create rpm package you need to follow the following steps: +To create an RPM package, execute the following from the command line: ```bash # Enter Packaging Directory $ cd packaging/rpm -# execute the script to generate tarballs +# Execute the script to generate tarballs $ ./make_rpm.sh ``` @@ -336,12 +337,12 @@ $ ./make_rpm.sh #### (Debian/Ubuntu) -To create deb package you need to follow the following steps: +To create a deb package, execute the following from the command line: ```bash # Enter Packaging Directory $ cd packaging/deb -# execute the script to generate tarballs +# Execute the script to generate tarballs $ ./make_deb.sh ``` @@ -575,10 +576,10 @@ The lowest value is taken as partition Id. ## How to contribute [![GitHub contributors](https://img.shields.io/github/contributors/ZigRazor/CXXGraph.svg)](https://GitHub.com/ZigRazor/CXXGraph/graphs/contributors/) -If you want give your support you can create a ***pull request*** [![GitHub pull-requests](https://img.shields.io/github/issues-pr/ZigRazor/CXXGraph.svg)](https://GitHub.com/ZigRazor/CXXGraph/pull/) or report an ***issue*** [![GitHub issues](https://img.shields.io/github/issues/ZigRazor/CXXGraph.svg)](https://GitHub.com/ZigRazor/CXXGraph/issues/). -If you want to change the code, or fix issue, or implement a new feature please read our [CONTRIBUTING Guide](https://github.com/ZigRazor/CXXGraph/blob/master/CONTRIBUTING.md) +If you want to give your support you can create a ***pull request*** [![GitHub pull-requests](https://img.shields.io/github/issues-pr/ZigRazor/CXXGraph.svg)](https://GitHub.com/ZigRazor/CXXGraph/pull/) or report an ***issue*** [![GitHub issues](https://img.shields.io/github/issues/ZigRazor/CXXGraph.svg)](https://GitHub.com/ZigRazor/CXXGraph/issues/). +If you want to change the code, fix an issue, or implement a new feature please read our [CONTRIBUTING Guide](https://github.com/ZigRazor/CXXGraph/blob/master/CONTRIBUTING.md). -If you want to disscuss new feature or you have any question or suggestion about library please open a [Discussion](https://github.com/ZigRazor/CXXGraph/discussions) or simply chat on [![Join the chat at https://gitter.im/CXXGraph-Community/community](https://badges.gitter.im/CXXGraph-Community/community.svg)](https://gitter.im/CXXGraph-Community/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +If you want to discuss new features or you have any questions or suggestions about the library, please open a [Discussion](https://github.com/ZigRazor/CXXGraph/discussions) or simply chat on [![Join the chat at https://gitter.im/CXXGraph-Community/community](https://badges.gitter.im/CXXGraph-Community/community.svg)](https://gitter.im/CXXGraph-Community/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Stars History @@ -590,7 +591,7 @@ If you want to disscuss new feature or you have any question or suggestion about ## Contact -E-Mail : zigrazor@gmail.com +E-mail : zigrazor@gmail.com [![Join the chat at https://gitter.im/CXXGraph-Community/community](https://badges.gitter.im/CXXGraph-Community/community.svg)](https://gitter.im/CXXGraph-Community/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) @@ -600,9 +601,9 @@ E-Mail : zigrazor@gmail.com ## Support -To support me just add ***Star*** the project [![GitHub stars](https://img.shields.io/github/stars/ZigRazor/CXXGraph.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/ZigRazor/CXXGraph/stargazers/) or ***follow me*** [![GitHub followers](https://img.shields.io/github/followers/ZigRazor.svg?style=social&label=Follow&maxAge=2592000)](https://github.com/ZigRazor?tab=followers) +To support me, add a ***Star*** to the project [![GitHub stars](https://img.shields.io/github/stars/ZigRazor/CXXGraph.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/ZigRazor/CXXGraph/stargazers/) or ***follow me*** [![GitHub followers](https://img.shields.io/github/followers/ZigRazor.svg?style=social&label=Follow&maxAge=2592000)](https://github.com/ZigRazor?tab=followers) -To get updated ***watch*** the project [![GitHub watchers](https://img.shields.io/github/watchers/ZigRazor/CXXGraph.svg?style=social&label=Watch&maxAge=2592000)](https://GitHub.com/ZigRazor/CXXGraph/watchers/) +To stay updated, ***watch*** the project [![GitHub watchers](https://img.shields.io/github/watchers/ZigRazor/CXXGraph.svg?style=social&label=Watch&maxAge=2592000)](https://GitHub.com/ZigRazor/CXXGraph/watchers/) ## References @@ -614,9 +615,9 @@ We are referenced by: ## Credits -Thanks to the community of [TheAlgorithms](https://github.com/TheAlgorithms) for some algorithms ispiration. +Thanks to the community of [TheAlgorithms](https://github.com/TheAlgorithms) for some algorithm inspiration. -Thanks to [GeeksForGeeks](https://www.geeksforgeeks.org/) for some algorithms inspiration. +Thanks to [GeeksForGeeks](https://www.geeksforgeeks.org/) for some algorithm inspiration. ## Contributors @@ -626,16 +627,16 @@ Thank you to all the people who have already contributed to CXXGraph! ## Cite Us -If you use this software please follow the [CITATION](https://github.com/ZigRazor/CXXGraph/blob/master/CITATION) istruction. +If you use this software please follow the [CITATION](https://github.com/ZigRazor/CXXGraph/blob/master/CITATION) instructions. Thank you! ## Hacktoberfest 2k21 -We have been participated at Hacktoberfest 2021, thank you to all the contributors! +We participated at Hacktoberfest 2021. Thank you to all the contributors! ## Hacktoberfest 2k22 -We have been participated at Hacktoberfest 2022, thank you to all the contributors! +We participated at Hacktoberfest 2022. Thank you to all the contributors! ## Other Details diff --git a/include/CXXGraph/Graph/Graph.hpp b/include/CXXGraph/Graph/Graph.hpp index 2312fa5ae..7bccd95d6 100644 --- a/include/CXXGraph/Graph/Graph.hpp +++ b/include/CXXGraph/Graph/Graph.hpp @@ -65,6 +65,7 @@ #include "CXXGraph/Utility/PointerHash.hpp" #include "CXXGraph/Utility/Reader.hpp" #include "CXXGraph/Utility/ThreadSafe.hpp" +#include "CXXGraph/Utility/TypeTraits.hpp" #include "CXXGraph/Utility/Typedef.hpp" #include "CXXGraph/Utility/Writer.hpp" @@ -181,6 +182,27 @@ class Graph { * */ virtual void addEdge(shared> edge); + /** + * \brief + * Function that adds any number of Edges to the Graph Edge set + * Note: This is the overload needed to terminate the + * recursion + * + * @param None + * + */ + template + void addEdges(); + /** + * \brief + * Function that adds any number of Edges to the Graph Edge set + * + * @param Raw pointers or shared pointers to the Edges + * + */ + template + std::enable_if && (is_edge_ptr_v && ...), void> addEdges( + T1 edge, Tn... edges); /** * \brief * Function to add a Node to the Graph Node Set @@ -199,6 +221,26 @@ class Graph { * */ virtual void addNode(shared> node); + /** + * \brief + * Function that adds any number of Nodes to the Graph Node set + * Note: This overload is needed to terminate the recursion + * + * @param None + * + */ + template + void addNodes(); + /** + * \brief + * Function that adds any number of Nodes to the Graph Node set + * + * @param Raw pointers or shared pointers to the Edges + * + */ + template + std::enable_if && (is_node_ptr_v && ...), void> addNodes( + T1 node, Tn... nodes); /** * \brief * Function remove an Edge from the Graph Edge Set @@ -898,7 +940,8 @@ template void Graph::addEdge(const Edge *edge) { if (edge->isDirected().has_value() && edge->isDirected().value()) { if (edge->isWeighted().has_value() && edge->isWeighted().value()) { - auto edge_shared = make_shared>(*edge); + auto edge_shared = make_shared>( + *dynamic_cast *>(edge)); this->edgeSet.insert(edge_shared); std::pair>, shared>> elem = { @@ -916,7 +959,8 @@ void Graph::addEdge(const Edge *edge) { } } else { if (edge->isWeighted().has_value() && edge->isWeighted().value()) { - auto edge_shared = make_shared>(*edge); + auto edge_shared = make_shared>( + *dynamic_cast *>(edge)); this->edgeSet.insert(edge_shared); std::pair>, shared>> elem = { @@ -966,6 +1010,20 @@ void Graph::addEdge(shared> edge) { } } +template +template +void Graph::addEdges() { + return; +} + +template +template +std::enable_if && (is_edge_ptr_v && ...), void> Graph::addEdges( + T1 edge, Tn... edges) { + addEdge(edge); + addEdges(edges...); +} + template void Graph::addNode(const Node *node) { auto node_shared = make_shared>(*node); @@ -977,6 +1035,20 @@ void Graph::addNode(shared> node) { this->isolatedNodesSet.insert(node); } +template +template +void Graph::addNodes() { + return; +} + +template +template +std::enable_if && (is_node_ptr_v && ...), void> Graph::addNodes( + T1 node, Tn... nodes) { + addNode(node); + addNodes(nodes...); +} + template void Graph::removeEdge(const CXXGraph::id_t edgeId) { auto edgeOpt = Graph::getEdge(edgeId); @@ -3417,36 +3489,39 @@ SCCResult Graph::kosaraju() const { visited.clear(); - std::function>, std::vector> &)> + std::function>, SCCResult, int)> dfs_helper1 = [this, &rev, &visited, &dfs_helper1](shared> source, - std::vector> &comp) { + SCCResult result, int sccLabel) { // mark the vertex visited visited[source->getId()] = true; // Add the current vertex to the strongly connected // component - comp.push_back(*source); + //comp.push_back(*source); + result.sccMap[source->getId()] = sccLabel; // travel the neighbors for (int i = 0; i < rev[source].size(); i++) { shared> neighbor = rev[source].at(i).first; if (visited[neighbor->getId()] == false) { // make recursive call from neighbor - dfs_helper1(neighbor, comp); + dfs_helper1(neighbor, result, sccLabel); } } }; + int sccLabel = 0; while (st.size() != 0) { auto rem = st.top(); st.pop(); if (visited[rem->getId()] == false) { - std::vector> comp; - dfs_helper1(rem, comp); - result.stronglyConnectedComps.push_back(comp); + //std::vector> comp; + dfs_helper1(rem, result, sccLabel); + sccLabel++; + //result.stronglyConnectedComps.push_back(comp); } } - + result.noOfComponents = sccLabel; result.success = true; return result; } diff --git a/include/CXXGraph/Utility/TypeTraits.hpp b/include/CXXGraph/Utility/TypeTraits.hpp new file mode 100755 index 000000000..3c47c36b5 --- /dev/null +++ b/include/CXXGraph/Utility/TypeTraits.hpp @@ -0,0 +1,78 @@ +/***********************************************************/ +/*** ______ ____ ______ _ ***/ +/*** / ___\ \/ /\ \/ / ___|_ __ __ _ _ __ | |__ ***/ +/*** | | \ / \ / | _| '__/ _` | '_ \| '_ \ ***/ +/*** | |___ / \ / \ |_| | | | (_| | |_) | | | | ***/ +/*** \____/_/\_\/_/\_\____|_| \__,_| .__/|_| |_| ***/ +/*** |_| ***/ +/***********************************************************/ +/*** Header-Only C++ Library for Graph ***/ +/*** Representation and Algorithms ***/ +/***********************************************************/ +/*** Author: ZigRazor ***/ +/*** E-Mail: zigrazor@gmail.com ***/ +/***********************************************************/ +/*** Collaboration: ----------- ***/ +/***********************************************************/ +/*** License: AGPL v3.0 ***/ +/***********************************************************/ + +#ifndef __CXXGRAPH_TYPE_TRAITS__ +#define __CXXGRAPH_TYPE_TRAITS__ + +#pragma once + +#include + +#include "CXXGraph/Edge/DirectedEdge.hpp" +#include "CXXGraph/Edge/DirectedWeightedEdge.hpp" +#include "CXXGraph/Edge/Edge.hpp" +#include "CXXGraph/Edge/UndirectedEdge.hpp" +#include "CXXGraph/Edge/UndirectedWeightedEdge.hpp" +#include "CXXGraph/Edge/Weighted.hpp" +#include "CXXGraph/Node/Node.hpp" + +namespace CXXGraph { + +// define is_node type trait for Nodes, Nodes pointers and shared pointers +template +struct is_node : std::false_type {}; + +template +struct is_node> : std::true_type {}; + +// define is_node_ptr type trait for Node pointers and shared pointers +template +struct is_node_ptr : std::false_type {}; + +template +struct is_node_ptr*> : std::true_type {}; + +template +struct is_node_ptr>> : std::true_type {}; + +template +inline constexpr bool is_node_ptr_v = is_node::value; + +// define is_edge type trait for Edges +template +struct is_edge : std::false_type {}; + +template +struct is_edge> : std::true_type {}; + +// define is_edge_ptr type trait for Edge pointers and shared pointers +template +struct is_edge_ptr : std::false_type {}; + +template +struct is_edge_ptr*> : std::true_type {}; + +template +struct is_edge_ptr>> : std::true_type {}; + +template +inline constexpr bool is_edge_ptr_v = is_edge::value; +} // namespace CXXGraph + +#endif diff --git a/include/CXXGraph/Utility/Typedef.hpp b/include/CXXGraph/Utility/Typedef.hpp index 7915a4457..90186bc86 100755 --- a/include/CXXGraph/Utility/Typedef.hpp +++ b/include/CXXGraph/Utility/Typedef.hpp @@ -197,7 +197,9 @@ struct SCCResult_struct { bool success = false; // TRUE if the function does not return error, FALSE otherwise std::string errorMessage = ""; // message of error - Components stronglyConnectedComps; + int noOfComponents = 0; + std::unordered_map sccMap; + //Components stronglyConnectedComps; }; template using SCCResult = SCCResult_struct; diff --git a/test/GraphTest.cpp b/test/GraphTest.cpp index 3641c8d1f..a475d0a59 100644 --- a/test/GraphTest.cpp +++ b/test/GraphTest.cpp @@ -1,4 +1,7 @@ +#include +#include +#include #include #include "CXXGraph/CXXGraph.hpp" @@ -207,6 +210,283 @@ TEST(GraphTest, RawAddEdge_3) { ASSERT_FALSE(graph.isUndirectedGraph()); } +TEST(GraphTest, AddEdgeWeight_raw) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::DirectedWeightedEdge edge1(1, node1, node2, 3); + CXXGraph::UndirectedWeightedEdge edge2(2, node1, node3, 5); + CXXGraph::Graph graph; + + graph.addEdge(&edge1); + graph.addEdge(&edge2); + + // Check that the edges are weighted + ASSERT_TRUE((*graph.getEdge(1))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(2))->isWeighted()); + // Check the value of the weights + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(1)) + ->getWeight(), + 3); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(2)) + ->getWeight(), + 5); +} + +TEST(GraphTest, AddEdgeWeight_shared) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::DirectedWeightedEdge edge1(1, node1, node2, 3); + CXXGraph::UndirectedWeightedEdge edge2(2, node1, node3, 5); + CXXGraph::Graph graph; + + graph.addEdge(make_shared>(edge1)); + graph.addEdge( + make_shared>(edge2)); + + // Check that the edges are weighted + ASSERT_TRUE((*graph.getEdge(1))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(2))->isWeighted()); + // Check the value of the weights + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(1)) + ->getWeight(), + 3); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(2)) + ->getWeight(), + 5); +} + +TEST(GraphTest, AddEdges_1) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::DirectedEdge edge1(1, node1, node2); + CXXGraph::DirectedEdge edge2(2, node1, node3); + CXXGraph::DirectedEdge edge3(3, node2, node3); + CXXGraph::Graph graph; + + graph.addEdges(&edge1, &edge2, &edge3); + + // Check the number of edges + ASSERT_EQ(graph.getEdgeSet().size(), 3); + // Check the number of nodes + ASSERT_EQ(graph.getNodeSet().size(), 3); +} + +TEST(GraphTest, AddEdges_1_shared) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::DirectedEdge edge1(1, node1, node2); + CXXGraph::DirectedEdge edge2(2, node1, node3); + CXXGraph::DirectedEdge edge3(3, node2, node3); + CXXGraph::Graph graph; + + auto edge1_shared = make_shared>(edge1); + auto edge2_shared = make_shared>(edge2); + auto edge3_shared = make_shared>(edge3); + graph.addEdges(edge1_shared, edge2_shared, edge3_shared); + + // Check the number of edges + ASSERT_EQ(graph.getEdgeSet().size(), 3); + // Check the number of nodes + ASSERT_EQ(graph.getNodeSet().size(), 3); +} + +TEST(GraphTest, AddEdges_2) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::UndirectedEdge edge1(1, node1, node2); + CXXGraph::UndirectedEdge edge2(2, node1, node3); + CXXGraph::UndirectedEdge edge3(3, node2, node3); + CXXGraph::Graph graph; + + graph.addEdges(&edge1, &edge2, &edge3); + + // Check the number of edges + ASSERT_EQ(graph.getEdgeSet().size(), 3); + // Check the number of nodes + ASSERT_EQ(graph.getNodeSet().size(), 3); +} + +TEST(GraphTest, AddEdges_2_shared) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::UndirectedEdge edge1(1, node1, node2); + CXXGraph::UndirectedEdge edge2(2, node1, node3); + CXXGraph::UndirectedEdge edge3(3, node2, node3); + CXXGraph::Graph graph; + + auto edge1_shared = make_shared>(edge1); + auto edge2_shared = make_shared>(edge2); + auto edge3_shared = make_shared>(edge3); + graph.addEdges(edge1_shared, edge2_shared, edge3_shared); + + // Check the number of edges + ASSERT_EQ(graph.getEdgeSet().size(), 3); + // Check the number of nodes + ASSERT_EQ(graph.getNodeSet().size(), 3); +} + +TEST(GraphTest, AddEdges_3) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::DirectedWeightedEdge edge1(1, node1, node2, 4); + CXXGraph::DirectedWeightedEdge edge2(2, node1, node3, 5); + CXXGraph::DirectedWeightedEdge edge3(3, node2, node3, 6); + CXXGraph::Graph graph; + + graph.addEdges(&edge1, &edge2, &edge3); + + // Check the number of edges + ASSERT_EQ(graph.getEdgeSet().size(), 3); + // Check the number of nodes + ASSERT_EQ(graph.getNodeSet().size(), 3); + + // Check that the edges are weighted + ASSERT_TRUE((*graph.getEdge(1))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(2))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(3))->isWeighted()); + // Check the value of the weights + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(1)) + ->getWeight(), + 4); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(2)) + ->getWeight(), + 5); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(3)) + ->getWeight(), + 6); +} + +TEST(GraphTest, AddEdges_3_shared) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::DirectedWeightedEdge edge1(1, node1, node2, 4); + CXXGraph::DirectedWeightedEdge edge2(2, node1, node3, 5); + CXXGraph::DirectedWeightedEdge edge3(3, node2, node3, 6); + CXXGraph::Graph graph; + + auto edge1_shared = + make_shared>(edge1); + auto edge2_shared = + make_shared>(edge2); + auto edge3_shared = + make_shared>(edge3); + graph.addEdges(edge1_shared, edge2_shared, edge3_shared); + + // Check the number of edges + ASSERT_EQ(graph.getEdgeSet().size(), 3); + // Check the number of nodes + ASSERT_EQ(graph.getNodeSet().size(), 3); + + // Check that the edges are weighted + ASSERT_TRUE((*graph.getEdge(1))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(2))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(3))->isWeighted()); + // Check the value of the weights + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(1)) + ->getWeight(), + 4); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(2)) + ->getWeight(), + 5); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(3)) + ->getWeight(), + 6); +} + +TEST(GraphTest, AddEdges_4) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::UndirectedWeightedEdge edge1(1, node1, node2, 4); + CXXGraph::UndirectedWeightedEdge edge2(2, node1, node3, 5); + CXXGraph::UndirectedWeightedEdge edge3(3, node2, node3, 6); + CXXGraph::Graph graph; + + graph.addEdges(&edge1, &edge2, &edge3); + + // Check the number of edges + ASSERT_EQ(graph.getEdgeSet().size(), 3); + // Check the number of nodes + ASSERT_EQ(graph.getNodeSet().size(), 3); + + // Check that the edges are weighted + ASSERT_TRUE((*graph.getEdge(1))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(2))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(3))->isWeighted()); + // Check the value of the weights + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(1)) + ->getWeight(), + 4); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(2)) + ->getWeight(), + 5); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(3)) + ->getWeight(), + 6); +} + +TEST(GraphTest, AddEdges_4_shared) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 1); + CXXGraph::Node node3("3", 1); + CXXGraph::UndirectedWeightedEdge edge1(1, node1, node2, 4); + CXXGraph::UndirectedWeightedEdge edge2(2, node1, node3, 5); + CXXGraph::UndirectedWeightedEdge edge3(3, node2, node3, 6); + CXXGraph::Graph graph; + + auto edge1_shared = + make_shared>(edge1); + auto edge2_shared = + make_shared>(edge2); + auto edge3_shared = + make_shared>(edge3); + graph.addEdges(edge1_shared, edge2_shared, edge3_shared); + + // Check the number of edges + ASSERT_EQ(graph.getEdgeSet().size(), 3); + // Check the number of nodes + ASSERT_EQ(graph.getNodeSet().size(), 3); + + // Check that the edges are weighted + ASSERT_TRUE((*graph.getEdge(1))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(2))->isWeighted()); + ASSERT_TRUE((*graph.getEdge(3))->isWeighted()); + // Check the value of the weights + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(1)) + ->getWeight(), + 4); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(2)) + ->getWeight(), + 5); + ASSERT_EQ( + std::dynamic_pointer_cast(*graph.getEdge(3)) + ->getWeight(), + 6); +} + TEST(GraphTest, DirectedEdgeCycle_1) { CXXGraph::Node node1("a", 1); CXXGraph::Node node2("b", 1); @@ -780,7 +1060,7 @@ TEST(InOutNodesTest, test_inOutEdges) { for (auto x : graph.inOutEdges(&node6)) { ASSERT_TRUE(x == make_shared>(edge6) || x == make_shared>(edge7) || - x == make_shared>(edge8)); + x == make_shared>(edge8)); } for (auto x : graph.inOutEdges(&node7)) { @@ -826,7 +1106,7 @@ TEST(InOutNodesTest, test_inOutEdges_shared) { for (auto x : graph.inOutEdges(node6_shared)) { ASSERT_TRUE(x == make_shared>(edge6) || x == make_shared>(edge7) || - x == make_shared>(edge8)); + x == make_shared>(edge8)); } auto node7_shared = make_shared>(node7); @@ -940,6 +1220,56 @@ TEST(IsolatedNodeGraphTest, Test_AddNode2) { ASSERT_EQ(graph.getEdgeSet().size(), 3); } +TEST(IsolatedNodeGraphTest, Test_AddNodes1) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + CXXGraph::DirectedEdge edge1(1, node1, node2); + CXXGraph::DirectedEdge edge2(2, node2, node1); + CXXGraph::DirectedEdge edge3(3, node1, node3); + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + CXXGraph::Graph graph(edgeSet); + + // Create an isolated node and add it to the graph + CXXGraph::Node node4("4", 4); + CXXGraph::Node node5("5", 5); + auto node4_shared = make_shared>(node4); + auto node5_shared = make_shared>(node5); + graph.addNodes(node4_shared, node5_shared); + + // Check that the number of nodes in the graph is 4 + ASSERT_EQ(graph.getNodeSet().size(), 5); + ASSERT_EQ(graph.getIsolatedNodeSet().size(), 2); + ASSERT_EQ(graph.getEdgeSet().size(), 3); +} + +TEST(IsolatedNodeGraphTest, Test_AddNodes2) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + CXXGraph::DirectedEdge edge1(1, node1, node2); + CXXGraph::DirectedEdge edge2(2, node2, node1); + CXXGraph::DirectedEdge edge3(3, node1, node3); + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + CXXGraph::Graph graph(edgeSet); + + // Create an isolated node and add it to the graph + CXXGraph::Node node4("4", 4); + CXXGraph::Node node5("5", 5); + graph.addNodes(&node4, &node5); + + // Check that the number of nodes in the graph is 4 + ASSERT_EQ(graph.getNodeSet().size(), 5); + ASSERT_EQ(graph.getIsolatedNodeSet().size(), 2); + ASSERT_EQ(graph.getEdgeSet().size(), 3); +} + TEST(TestRemoveNode, Test_isolatedNode) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); diff --git a/test/KosarajuTest.cpp b/test/KosarajuTest.cpp index a17f1f4c2..a3c129719 100644 --- a/test/KosarajuTest.cpp +++ b/test/KosarajuTest.cpp @@ -13,22 +13,16 @@ using std::make_shared; // helper function to compare strongly connected components (SCC) as computed // by the algorithm with expected (correct) SCC -void compareComponents(CXXGraph::Components& comp1, +void compareComponents(CXXGraph::SCCResult result, CXXGraph::Components& comp2) { - ASSERT_EQ(comp1.size(), comp2.size()); + ASSERT_EQ(result.noOfComponents, comp2.size()); - for (size_t i = 0; i < comp1.size(); ++i) { - std::sort(comp1[i].begin(), comp1[i].end()); - std::sort(comp2[i].begin(), comp2[i].end()); + for(int i=0;i edgeSet; edgeSet.insert(make_shared>(edge)); CXXGraph::Graph graph(edgeSet); - auto res = graph.kosaraju(); - ASSERT_EQ(res.stronglyConnectedComps.size(), 0); + CXXGraph::SCCResult res = graph.kosaraju(); + ASSERT_EQ(res.noOfComponents, 0); ASSERT_FALSE(res.success); ASSERT_EQ(res.errorMessage, CXXGraph::ERR_UNDIR_GRAPH); } @@ -55,11 +49,11 @@ TEST(KosarajuTest, test_2) { edgeSet.insert(make_shared>(edge1)); edgeSet.insert(make_shared>(edge2)); CXXGraph::Graph graph(edgeSet); - auto res = graph.kosaraju(); + CXXGraph::SCCResult res = graph.kosaraju(); ASSERT_TRUE(res.success); ASSERT_EQ(res.errorMessage, ""); - ASSERT_EQ(res.stronglyConnectedComps.size(), 1); - ASSERT_EQ(res.stronglyConnectedComps[0].size(), 2); + ASSERT_EQ(res.noOfComponents, 1); + //ASSERT_EQ(res.stronglyConnectedComps[0].size(), 2); } // 1 comp, 2 strongly connected comp @@ -75,12 +69,12 @@ TEST(KosarajuTest, test_3) { edgeSet.insert(make_shared>(edge2)); edgeSet.insert(make_shared>(edge3)); CXXGraph::Graph graph(edgeSet); - auto res = graph.kosaraju(); + CXXGraph::SCCResult res = graph.kosaraju(); ASSERT_TRUE(res.success); ASSERT_EQ(res.errorMessage, ""); CXXGraph::Components expectedComponents = {{node1, node2}, {node3}}; - compareComponents(res.stronglyConnectedComps, expectedComponents); + compareComponents(res, expectedComponents); } // 2 components, 2 strongly connected comps @@ -99,12 +93,12 @@ TEST(KosarajuTest, test_4) { edgeSet.insert(make_shared>(edge3)); edgeSet.insert(make_shared>(edge4)); CXXGraph::Graph graph(edgeSet); - auto res = graph.kosaraju(); + CXXGraph::SCCResult res = graph.kosaraju(); ASSERT_TRUE(res.success); ASSERT_EQ(res.errorMessage, ""); CXXGraph::Components expectedComponents = {{node1, node2}, {node3, node4}}; - compareComponents(res.stronglyConnectedComps, expectedComponents); + compareComponents(res, expectedComponents); } TEST(KosarajuTest, test_5) { @@ -168,7 +162,7 @@ TEST(KosarajuTest, test_5) { edgeSet.insert(make_shared>(edge21)); CXXGraph::Graph graph(edgeSet); - auto res = graph.kosaraju(); + CXXGraph::SCCResult res = graph.kosaraju(); ASSERT_TRUE(res.success); ASSERT_EQ(res.errorMessage, ""); @@ -179,5 +173,5 @@ TEST(KosarajuTest, test_5) { {node8, node9}, {node10, node11, node12, node13}}; - compareComponents(res.stronglyConnectedComps, expectedComponents); + compareComponents(res, expectedComponents); }