diff --git a/include/Algorithms/GraphTraversal/BreadthFirstSearch.hpp b/include/Algorithms/GraphTraversal/BreadthFirstSearch.hpp new file mode 100644 index 00000000..e4710a07 --- /dev/null +++ b/include/Algorithms/GraphTraversal/BreadthFirstSearch.hpp @@ -0,0 +1,133 @@ +/* + * BreadthFirstSearch.hpp + * + * Created on: Jan 27, 2019 + * Author: Franziska Wegner + */ +#ifndef EGOA__ALGORITHMS__GRAPH_TRAVERSAL__BREADTH_FIRST_SEARCH__HPP +#define EGOA__ALGORITHMS__GRAPH_TRAVERSAL__BREADTH_FIRST_SEARCH__HPP + +#include "Algorithms/GraphTraversal/Traversal.hpp" +#include "DataStructures/Container/Queues/StdQueue.hpp" + +namespace egoa { + +/** + * @brief Class for the Breadth-First Search (BFS). + * @details BFS uses a queue that processes the vertices in First-in, + * First-out (FiFo) order. Thus, the traversal of a graph is level-wise. + * Not that if the graph G=(V,E) is undirected chords (non-tree edges) can + * only be between vertices on the same level or one level below (as the + * vertex would have been visited in the next step). For directed graphs, + * an chord (u,v) in E can only exists if v's level is higher (closer to + * the source vertex s) than u's. + * + * The run time is in O(n + m). + * + * @pre The queue uses the Type Types::vertexId. Note that the queue + * does not need to implement the element-wise loops. + * + * @tparam GraphType The graph should at least provide the same interface + * as the StaticGraph(). + * @tparam QueueType The queue should provide the same interface as Queue(). + * @tparam IsDirected If @p true the graph is treated as a directed graph, + * if @p false the graph is treated as an undirected graph. + */ +template< typename GraphType = StaticGraph,Edges::ElectricalProperties> + , typename QueueType = StdQueue + , bool IsDirected= false > +class BFS final : Traversal { + public: + // Type aliasing + using TQueue = QueueType; + + public: +#pragma mark CONSTRUCTOR_AND_DESTRUCTOR + BFS ( TGraph const & graph, TVertex source ) + : TTraversal ( graph, source ) + , queue_() + {} + + virtual ~BFS() {} + +#pragma mark BREADTH_FIRST_SEARCH + /** + * @brief Run Breadth-First search (BFS). + */ + virtual inline void Run() { + ESSENTIAL_ASSERT ( queue_.Empty() ); + + EnqueueVertexWith ( source_ ); + SetVertexVisitedAt ( source_ ); + + while ( !queue_.Empty() ) { + ESSENTIAL_ASSERT ( queue_.Empty() ); + TVertex sourceId = DequeueVertex(); + ESSENTIAL_ASSERT ( graph_.VertexExists ( sourceId ) ); + ESSENTIAL_ASSERT ( VisitedVertexAt ( sourceId ) ); + + PreprocessingVertexWith ( sourceId ); + SetVertexProcessedAt ( sourceId ); + + for_all_edges_at( sourceId, []( ElectricalEdge & edge ) { + TVertex targetId = edge.Other ( sourceId ); + ESSENTIAL_ASSERT ( graph_.VertexExists ( targetId ) ); + + if ( !ProcessedVertexAt( targetId ) || graph_.IsDirected() ) { + ProcessingEdgeWith ( edge.Identifier() ); + } + if ( !VisitedVertexAt( targetId ) ) { + EnqueueVertexWith ( targetId ); + SetVertexVisitedAt ( targetId ); + ParentOf ( targetId ) = sourceId; + } + }); + PostprocessingVertexWith ( sourceId ); + } + } + + private: +#pragma mark QUEUE_METHODS + /** + * @brief Add a vertex to the queue. + * @pre Only visited vertices that are unprocessed should be + * add to the queue. + * + * @param[in] vertexId The vertex identifier. + */ + inline void EnqueueVertexWith ( TVertex vertexId ) { + USAGE_ASSERT ( graph_.VertexExists ( vertexId ) ); + queue_.Push ( vertexId ); + } + + /** + * @brief Get the next unprocessed vertex. + * @details A vertex can only be dequeued if it is was marked as + * visited. + * + * @return The next unprocessed but visited vertex. + */ + inline TVertex DequeueVertex ( ) { + USAGE_ASSERT ( graph_.VertexExists ( vertexId ) ); + TVertex vertexId = queue_.front(); + queue_.Pop(); + return vertexId; + } + +//exact behavior of the Breadth-First Search (BFS) depends on the processing methods +#pragma mark FURTHER_PROCESSING + virtual inline void PreprocessingVertexWith ( TVertex vertexId ) override {} + virtual inline void PostprocessingVertexWith ( TVertex vertexId ) override {} + virtual inline void ProcessingEdgeWith ( TVertex sourceId + , TVertex targetId ) override {} + +#pragma mark MEMBERS + private: + TQueue queue_; /**< The FIFO queue */ + +}; // class BFS + +} // namespace egoa + + +#endif // EGOA__ALGORITHMS__GRAPH_TRAVERSAL__BREADTH_FIRST_SEARCH__HPP diff --git a/include/Algorithms/GraphTraversal/DepthFirstSearch.hpp b/include/Algorithms/GraphTraversal/DepthFirstSearch.hpp new file mode 100644 index 00000000..576bc142 --- /dev/null +++ b/include/Algorithms/GraphTraversal/DepthFirstSearch.hpp @@ -0,0 +1,294 @@ +/* + * DFS.hpp + * + * Created on: Feb 17, 2019 + * Author: Franziska Wegner + */ +#ifndef EGOA__ALGORITHMS__GRAPH_TRAVERSAL__DEPTH_FIRST_SEARCH__HPP +#define EGOA__ALGORITHMS__GRAPH_TRAVERSAL__DEPTH_FIRST_SEARCH__HPP + +#include "Algorithms/GraphTraversal/Traversal.hpp" + +#include "Exceptions/Assertions.hpp" + +namespace egoa { + +enum class DfsEdgeType { + tree = 0 + , backward = 1 + , forward = 2 + , cross = 3 + , none = 99 +}; + +/** + * @brief Class for the Depth-First Search (DFS). + * + * @tparam GraphType The graph should at least provide the same interface + * as the StaticGraph. + * @tparam IsDirected If @p true the graph is treated as a directed graph, + * if @p false the graph is treated as an undirected graph. + */ +template< typename GraphType + , bool IsDirected = false + , bool Recursive = true > +class DepthFirstSearch : public Traversal { + public: + using TGraph = GraphType; + using TVertexId = typename TGraph::TVertexId; + using TTime = Types::count; + + ///@name Constructors and destructor + ///@{ +#pragma mark CONSTRUCTOR_AND_DESTRUCTOR + + /** + * @brief Constructs a new DFS instance. + * + * @param graph The graph + * @param[in] source The source + */ + DepthFirstSearch ( TGraph const & graph + , TVertexId source ) + : Traversal ( graph, source ) + , time_( 0 ) + , terminate_( false ) + , entryTime_( std::vector( graph.NumberOfVertices(), 0 ) ) + , exitTime_( std::vector( graph.NumberOfVertices(), 0 ) ) + {} + + virtual ~DepthFirstSearch () {} + ///@} + +#pragma mark DEPTH_FIRST_SEARCH + inline void Run() + { + // Recursive call + auto dfs = [this] ( TVertexId source, auto const & dfs ) + { + if ( Terminate() ) return; // Search termination + + entryTime_[source] = Time(); + ++Time(); + + this->SetVertexVisitedAt( source ); + PreprocessingVertexWith ( source ); + + this->breakable_for_all_edges_at ( source, + [source, &dfs, this]( typename GraphType::TEdge const & edge ) + { + TVertexId target = edge.Other ( source ); + + // Ignore edges that directly lead back to the parent + if ( this->ParentOf( source ) == target ) return true; + + bool targetVisited = this->VisitedVertexAt( target ); + + if ( !targetVisited ) + { + this->ParentOf( target ) = source; + dfs ( target, dfs ); + } else /* not processed */ + { // Cycle edge + ProcessingEdgeWith( source, target, edge.Identifier() ); + } + + PostprocessingEdgeWith( source, target, edge.Identifier() ); + + // Search termination by returning false in the breakable loop + bool toContinue = !this->Terminate(); + return toContinue; + } + ); + if ( Terminate() ) return; // Search termination + + exitTime_[ source ] = Time(); + ++Time(); + + PostprocessingVertexWith ( source ); + this->SetVertexProcessedAt ( source ); + }; + + dfs ( this->Source(), dfs ); + } + + public: +#pragma mark DFS_EDGE_TYPE + /** + * @brief Determine DFS edge type. + * + * @param[in] source The source identifier. + * @param[in] target The target identifier. + * + * @return The DFS edge type. + * + * @todo Cross edge is only possible in directed case -> check for graph type + */ + inline DfsEdgeType TypifyEdge ( TVertexId source, TVertexId target ) + { + // Tree edge + if ( source == this->ParentOf ( target ) ) + { + return DfsEdgeType::tree; + } + + // Backward edge + if ( this->VisitedVertexAt ( target ) + && !this->ProcessedVertexAt ( target ) ) + { + return DfsEdgeType::backward; + } + + // Forward edge + if ( this->ProcessedVertexAt ( target ) + && EntryTimeAt ( target ) > EntryTimeAt ( source ) ) + { + return DfsEdgeType::forward; + } + + // Cross edge + if ( this->ProcessedVertexAt ( target ) + && EntryTimeAt ( target ) < EntryTimeAt ( source ) ) return DfsEdgeType::cross; + + // None of them -> should not happening + ESSENTIAL_ASSERT( false && "DFS edge type is none." ); + } + +#pragma mark GETTER_AND_SETTER + + /** + * @brief Terminate the DFS + * + * @return TRUE if the DFS + */ + inline bool Terminate() const { return terminate_; } + inline void SetTerminate() { terminate_ = true; } + + private: + +#pragma mark TIMERS + /** + * @brief Modify time counter + * + * @return Current time + */ + ///@{ + inline TTime Time() const { return time_; } + inline TTime & Time() { return time_; } + ///@} + + public: + /** + * @brief { function_description } + * + * @param vertex The vertex + * + * @return { description_of_the_return_value } + */ + inline TTime EntryTimeAt ( TVertexId vertexId ) const + { + return entryTime_[vertexId]; + } + + /** + * @brief Returns the exit time of a vertex. + * + * @param vertexId The vertex identifier. + * + * @return The exit time for a vertex during the DFS. + */ + inline TTime ExitTimeAt ( TVertexId const vertexId ) const + { + return exitTime_[vertexId]; + } + + +//exact behavior of the Depth-First Search (DFS) depends on the processing methods +#pragma mark FURTHER_PROCESSING + + /** + * @brief Preprocessing the vertex with @p vertexId. + * + * @param[in] vertexId The vertex identifier. + * @param[in] function The function object that is called for the + * vertexId, e.g., a lambda function. + * + * @tparam FUNCTION The function object that is called for + * the vertex identifiers @p vertexId. + */ + // template + virtual + inline + void PreprocessingVertexWith ( TVertexId vertexId + // , FUNCTION function + ) + { + // function ( vertexId ); + } + + /** + * @brief Post processing the vertex with @p vertexId. + * + * @param[in] vertexId The vertex identifier. + * @param[in] function The function object that is called for the + * vertexId, e.g., a lambda function. + * + * @tparam FUNCTION The function object that is called for + * the vertex identifiers @p vertexId. + */ + // template + virtual + inline + void PostprocessingVertexWith ( TVertexId vertexId + // , FUNCTION function + ) + { + // function ( vertexId ); + } + + // template + virtual + inline + void ProcessingEdgeWith ( TVertexId source + , TVertexId target + , Types::edgeId edgeId + // , FUNCTION function + ) + { + // function ( source, target, edgeId ); + } + + /** + * @brief Post processing the edge with @p edgeId. + * + * @param[in] vertexId The vertex identifier. + * @param[in] function The function object that is called for the + * vertexId, e.g., a lambda function. + * + * @tparam FUNCTION The function object that is called for + * the edge identifiers @p edgeId. + */ + // template + virtual + inline + void PostprocessingEdgeWith ( TVertexId source + , TVertexId target + , Types::edgeId edgeId + // , FUNCTION function + ) + { + // function ( source, target, edgeId ); + } + +#pragma mark MEMBERS + private: + TTime time_; /**< Current time counter */ + bool terminate_; /**< Terminate search */ + + std::vector entryTime_; /**< Entry time at a vertex */ + std::vector exitTime_; /**< Exit time at a vertex */ +}; // class DepthFirstSearch + +} // namespace egoa + +#endif // EGOA__ALGORITHMS__GRAPH_TRAVERSAL__DEPTH_FIRST_SEARCH__HPP \ No newline at end of file diff --git a/include/Algorithms/GraphTraversal/Traversal.hpp b/include/Algorithms/GraphTraversal/Traversal.hpp new file mode 100644 index 00000000..2a513cbf --- /dev/null +++ b/include/Algorithms/GraphTraversal/Traversal.hpp @@ -0,0 +1,342 @@ +/* + * Traversal.hpp + * + * Created on: Feb 18, 2019 + * Author: Franziska Wegner + */ +#ifndef EGOA__ALGORITHMS__GRAPH_TRAVERSAL__TRAVERSAL__HPP +#define EGOA__ALGORITHMS__GRAPH_TRAVERSAL__TRAVERSAL__HPP + +#include + +#include "Auxiliary/Constants.hpp" +#include "Auxiliary/ExecutionPolicy.hpp" + +#include "Exceptions/Assertions.hpp" + +namespace egoa{ + +namespace internal { + +template< typename GraphType, bool IsDirected > +class GraphTypeLoopDifferentiation; + +} // namespace internal + +/** + * @brief Interface for graph traversal. + * + * @tparam GraphType GraphType The graph should at least provide the same interface + * as the StaticGraph(). + * @tparam IsDirected If @p true the graph is treated as a directed graph, + * if @p false the graph is treated as an undirected graph. + */ +template< typename GraphType, + bool IsDirected = false > +class Traversal { + public: + using TGraph = GraphType; + using TVertexId = typename GraphType::TVertexId; + + ///@name Constructors and destructor + ///@{ +#pragma mark CONSTRUCTOR_AND_DESTRUCTOR + + /** + * @brief Constructs a new instance. + * + * @param graph The graph + * @param[in] source The source + */ + Traversal ( TGraph const & graph, TVertexId source ) + : graph_ ( graph ) + , source_ ( source ) + , visited_ ( std::vector( graph.NumberOfVertices(), false ) ) + , processed_( std::vector( graph.NumberOfVertices(), false ) ) + , parent_ ( std::vector( graph.NumberOfVertices(), Const::NONE ) ) {} + + virtual ~Traversal() {} + ///@} + +#pragma mark GETTER_AND_SETTER + /** + * @brief Getter and setter for the source vertex. + * + * @return The source's identifier. + */ + ///@{ + inline TVertexId Source() const { return source_; } + inline TVertexId & Source() { return source_; } + ///@} + +#pragma mark RESULT_EXTRACTION + virtual inline void Result ( std::vector parent ) + { + // @todo Implement, see MST + throw std::runtime_error("Not implemented yet!"); + } + + protected: + + ///@name Vertex visited methods + ///@{ +#pragma mark VERTEX_VISITED_METHODS + /** + * @brief Sets the vertex at @p vertexId to visited. + * + * @param[in] vertexId The vertex identifier. + */ + inline void SetVertexVisitedAt ( TVertexId vertexId ) + { + USAGE_ASSERT ( graph_.VertexExists ( vertexId ) ); + visited_[vertexId] = true; + } + + /** + * @brief Getter and setter to access the visited field. + * @details A vertex is visited if it is traversed (touched) for + * the first time (added to the queue). + * + * @param[in] vertexId The vertex identifier. + * + * @return @p true if the vertex was visited, otherwise @p false. + */ + inline bool VisitedVertexAt ( TVertexId vertexId ) const + { + USAGE_ASSERT ( graph_.VertexExists ( vertexId ) ); + return visited_[vertexId]; + } + ///@} + + ///@name Vertex processed methods + ///@{ +#pragma mark VERTEX_PROCESSED_METHODS + /** + * @brief Sets the vertex at @p vertexId to processed. + * + * @param[in] vertexId The vertex identifier. + */ + inline void SetVertexProcessedAt ( TVertexId vertexId ) + { + USAGE_ASSERT ( graph_.VertexExists ( vertexId ) ); + processed_[vertexId] = true; + } + + /** + * @brief Getter and setter to access the process field. + * @details A vertex is processed if it is removed from the queue. + * Note that this means all its children will be visited + * subsequently. + * + * @param[in] vertexId The vertex identifier. + * + * @return @p true if the vertex is processed, otherwise @p false. + */ + inline bool ProcessedVertexAt ( TVertexId vertexId ) const + { + USAGE_ASSERT ( graph_.VertexExists ( vertexId ) ); + return processed_[vertexId]; + } + ///@} + + public: +#pragma mark PARENT_METHODS + /** + * @brief Getter and setter for the parent relation + * + * @param[in] vertexId The vertex identifier. + * + * @return The vertex identifier of the parent. + */ + ///@{ + inline TVertexId & ParentOf ( TVertexId vertexId ) + { + USAGE_ASSERT ( graph_.VertexExists ( vertexId ) ); + return parent_[vertexId]; + } + + inline TVertexId ParentOf ( TVertexId vertexId ) const + { + USAGE_ASSERT ( graph_.VertexExists ( vertexId ) ); + return parent_[vertexId]; + } + ///@} + + ///@name Pre and post processing methods + ///@{ +#pragma mark FURTHER_PROCESSING + + // virtual inline void PreprocessingVertexWith ( TVertexId vertex ) = 0; + // virtual inline void PostprocessingVertexWith ( TVertexId vertex ) = 0; + // virtual inline void ProcessingEdgeWith ( TVertexId source, + // TVertexId target, + // Types::edgeId edgeId ) = 0; + ///@} + + protected: +#pragma mark OTHER_METHODS + /** + * @brief Clear and resize all vectors + */ + inline void Clear () + { + visited_.clear (); + visited_.resize ( graph_.NumberOfVertices(), false ); + + processed_.clear (); + processed_.resize ( graph_.NumberOfVertices(), false ); + + parent_.clear (); + parent_.resize ( graph_.NumberOfVertices(), Const::NONE ); + } + + inline bool VertexExists ( TVertexId vertexId ) + { + return graph_.VertexExists ( vertexId ); + } + + inline bool NumberOfVertices() + { + return graph_.NumberOfVertices ( ); + } + + /** + * @name Edge iterators. + * @details If the template parameter @p IsDirected is set to true + * the iterators loop over outgoing edges of the vertex only, + * otherwise it loops over all edges at the vertex. + */ + ///@{ +#pragma mark LOOPS + /** + * @brief The @p for loop over all (outgoing) edges that is + * breakable. + * + * @param vertexId The vertex identifier. + * @param[in] function The function, e.g., lambda function. + * + * @code{.cpp} + * breakable_for_all_edges_at( + * []( TEdge const & edge ) + * { + * // Do something with the edge object. + * } + * ); + * @endcode + * + * @tparam FUNCTION The function object that is called for + * all incident (outgoing) edges at @p vertexId. + */ + template + inline void breakable_for_all_edges_at ( TVertexId const & vertexId + , FUNCTION function ) const + { + internal::GraphTypeLoopDifferentiation + ::breakable_for_all_edges_at ( graph_, vertexId, function ); + } + + /** + * @brief The @p for loop over all (outgoing) edges. + * + * @param vertexId The vertex identifier. + * @param[in] function The function + * + * @code{.cpp} + * for_all_edges_at ( vertexId + * , []( TEdge const & edge ) + * { + * // Do something with the edge object. + * } + * ); + * @endcode + * + * @tparam FUNCTION The function object that is called for + * all incident (outgoing) edges at @p vertexId. + */ + template + inline void for_all_edges_at ( TVertexId const & vertexId + , FUNCTION function ) const + { + internal::GraphTypeLoopDifferentiation + ::for_all_edges_at ( graph_, vertexId, function ); + } + ///@} +#pragma mark FRIEND + private: + friend class internal::GraphTypeLoopDifferentiation; + friend class internal::GraphTypeLoopDifferentiation; + +#pragma mark MEMBERS + private: + TGraph const & graph_; /**< The graph G=(V,E) */ + + TVertexId source_; /**< Source vertex from which BFS starts */ + std::vector visited_; /**< Vertex already visited */ + std::vector processed_; /**< Vertex already processed */ + std::vector parent_; /**< BFS structure in form of parent pointers */ +}; + +namespace internal { + +#pragma mark DIRECTED_GRAPH_LOOP + +template +class GraphTypeLoopDifferentiation< GraphType, true > { + // Type aliasing + using TGraph = GraphType; + using TVertexId = typename GraphType::TVertexId; + + public: + template + static inline + void breakable_for_all_edges_at ( TGraph const & graph + , TVertexId const & vertex + , FUNCTION function ) + { + graph.template for_out_edges_at ( vertex, function ); + } + + template + static inline + void for_all_edges_at ( TGraph const & graph + , TVertexId const & vertex + , FUNCTION function ) + { + graph.template for_out_edges_at ( vertex, function ); + } +}; + +#pragma mark UNDIRECTED_GRAPH_LOOP + +template +class GraphTypeLoopDifferentiation< GraphType, false > { + // Type aliasing + using TGraph = GraphType; + using TVertexId = typename GraphType::TVertexId; + + public: + template + static inline + void breakable_for_all_edges_at ( TGraph const & graph + , TVertexId const & vertex + , FUNCTION function ) + { + graph.template for_all_edges_at ( vertex, function ); + } + + template + static inline + void for_all_edges_at ( TGraph & graph + , TVertexId const & vertex + , FUNCTION function ) + { + graph.template for_all_edges_at ( vertex, function ); + } +}; + +} // namespace internal + +} // namespace Traversal + + +#endif // EGOA__ALGORITHMS__GRAPH_TRAVERSAL__TRAVERSAL__HPP