From f2e7b93b02b56792b8a95963e2f804354591f540 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Uhl=C3=ADk?= <jan@uhlik.me>
Date: Thu, 29 Mar 2018 20:55:53 +0200
Subject: [PATCH] Add DFS algorithm.

---
 alib2graph_algo/src/traverse/DFS.cpp | 122 ++++++++++++++++
 alib2graph_algo/src/traverse/DFS.hpp | 204 +++++++++++++++++++++++++++
 2 files changed, 326 insertions(+)
 create mode 100644 alib2graph_algo/src/traverse/DFS.cpp
 create mode 100644 alib2graph_algo/src/traverse/DFS.hpp

diff --git a/alib2graph_algo/src/traverse/DFS.cpp b/alib2graph_algo/src/traverse/DFS.cpp
new file mode 100644
index 0000000000..d7055514cc
--- /dev/null
+++ b/alib2graph_algo/src/traverse/DFS.cpp
@@ -0,0 +1,122 @@
+// DFS.cpp
+//
+//     Created on: 27. 02. 2018
+//         Author: Jan Uhlik
+//    Modified by:
+//
+// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
+// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library
+
+#include "DFS.hpp"
+
+#include <registration/AlgoRegistration.hpp>
+#include <graph/GraphClasses.hpp>
+#include <grid/GridClasses.hpp>
+
+namespace {
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Normal Graph
+
+auto DFS1 = registration::AbstractRegister<traverse::DFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::UndirectedGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto DFS2 = registration::AbstractRegister<traverse::DFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::UndirectedMultiGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto DFS3 = registration::AbstractRegister<traverse::DFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::DirectedGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto DFS4 = registration::AbstractRegister<traverse::DFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::DirectedMultiGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto DFS5 = registration::AbstractRegister<traverse::DFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::MixedGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto DFS6 = registration::AbstractRegister<traverse::DFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::MixedMultiGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto DFSGrid1 = registration::AbstractRegister<traverse::DFS,
+                                               ext::vector<DefaultSquareGridNodeType>,
+                                               const grid::SquareGrid4<> &,
+                                               const DefaultSquareGridNodeType &,
+                                               const DefaultSquareGridNodeType &>(traverse::DFS::findPathRegistration);
+
+auto DFSGrid2 = registration::AbstractRegister<traverse::DFS,
+                                               ext::vector<DefaultSquareGridNodeType>,
+                                               const grid::SquareGrid8<> &,
+                                               const DefaultSquareGridNodeType &,
+                                               const DefaultSquareGridNodeType &>(traverse::DFS::findPathRegistration);
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Weighted Graph
+
+auto WDFS1 = registration::AbstractRegister<traverse::DFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedUndirectedGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto WDFS2 = registration::AbstractRegister<traverse::DFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedUndirectedMultiGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto WDFS3 = registration::AbstractRegister<traverse::DFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedDirectedGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto WDFS4 = registration::AbstractRegister<traverse::DFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedDirectedMultiGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto WDFS5 = registration::AbstractRegister<traverse::DFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedMixedGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto WDFS6 = registration::AbstractRegister<traverse::DFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedMixedMultiGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::DFS::findPathRegistration);
+
+auto WDFSGrid1 = registration::AbstractRegister<traverse::DFS,
+                                                ext::vector<DefaultSquareGridNodeType>,
+                                                const grid::WeightedSquareGrid4<> &,
+                                                const DefaultSquareGridNodeType &,
+                                                const DefaultSquareGridNodeType &>(traverse::DFS::findPathRegistration);
+
+auto WDFSGrid2 = registration::AbstractRegister<traverse::DFS,
+                                                ext::vector<DefaultSquareGridNodeType>,
+                                                const grid::WeightedSquareGrid8<> &,
+                                                const DefaultSquareGridNodeType &,
+                                                const DefaultSquareGridNodeType &>(traverse::DFS::findPathRegistration);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+}
diff --git a/alib2graph_algo/src/traverse/DFS.hpp b/alib2graph_algo/src/traverse/DFS.hpp
new file mode 100644
index 0000000000..db95256e2e
--- /dev/null
+++ b/alib2graph_algo/src/traverse/DFS.hpp
@@ -0,0 +1,204 @@
+// DFS.hpp
+//
+//     Created on: 27. 02. 2018
+//         Author: Jan Uhlik
+//    Modified by:
+//
+// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
+// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library
+
+#ifndef ALIB2_DFS_HPP
+#define ALIB2_DFS_HPP
+
+#include <functional>
+#include <alib/vector>
+#include <queue>
+#include <alib/set>
+#include <alib/map>
+
+#include <common/ReconstructPath.hpp>
+
+namespace traverse {
+
+class DFS {
+// ---------------------------------------------------------------------------------------------------------------------
+
+ public:
+
+  /// Run DFS algorithm from the \p start node in the \p graph.
+  ///
+  /// Whenever node is opened, \p f_user is called with two parameters (the opened node and distance to this node).
+  /// If return of \p f_user is true, then the algorithm is stopped.
+  ///
+  /// \param graph to explore.
+  /// \param start initial node.
+  /// \param f_user function which is called for every opened node with value of currently shortest path.
+  ///
+  template<
+      typename TGraph,
+      typename TNode,
+      typename F = std::function<bool(const TNode &, const size_t &)>>
+  static
+  void
+  run(const TGraph &graph,
+      const TNode &start,
+      F f_user = [](const TNode &, const size_t &) -> bool { return false; });
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  /// Find path using DFS algorithm from the \p start node to the \p goal node in the \p graph.
+  /// However, it is not quarantee that the return path gonna be the shortest one.
+  ///
+  /// Whenever node is opened, \p f_user is called with two parameters (the opened node and distance to this node).
+  ///
+  /// \param graph to explore.
+  /// \param start initial node.
+  /// \param goal final node.
+  /// \param f_user function which is called for every opened node with value of currently shortest path.
+  ///
+  /// \returns nodes in path, if there is no such path vector is empty.
+  ///
+  template<
+      typename TGraph,
+      typename TNode,
+      typename F = std::function<void(const TNode &, const size_t &)>>
+  static
+  ext::vector<TNode>
+  findPath(const TGraph &graph,
+           const TNode &start,
+           const TNode &goal,
+           F f_user = [](const TNode &, const size_t &) {});
+
+  template<typename TGraph, typename TNode>
+  static
+  ext::vector<TNode>
+  findPathRegistration(const TGraph &graph,
+                       const TNode &start,
+                       const TNode &goal) {
+    return findPath(graph, start, goal);
+
+  }
+
+// =====================================================================================================================
+
+ private:
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TNode>
+  struct Data {
+    ext::map<TNode, size_t> d; // distance
+    ext::set<TNode> v; // visited
+    ext::map<TNode, TNode> p; // parents
+  };
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TGraph, typename TNode, typename F1, typename F2>
+  static
+  ext::vector<TNode>
+  impl(const TGraph &graph,
+       const TNode &start,
+       const TNode &goal,
+       F1 f_user,
+       F2 f_stop);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TGraph, typename TNode, typename F1, typename F2>
+  static
+  bool
+  expansion(const TGraph &graph,
+            DFS::Data<TNode> &data,
+            const TNode &n,
+            const TNode &p,
+            F1 f_user,
+            F2 f_stop);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+};
+
+// =====================================================================================================================
+
+template<typename TGraph, typename TNode, typename F>
+void DFS::run(const TGraph &graph, const TNode &start, F f_user) {
+  impl(graph, start, start, f_user, [](const TNode &) -> bool { return false; });
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TGraph, typename TNode, typename F>
+ext::vector<TNode> DFS::findPath(const TGraph &graph, const TNode &start, const TNode &goal, F f_user) {
+  return impl(graph, start, goal,
+              [&](const TNode &n, const auto &d) -> bool {
+                f_user(n, d);
+                return false;
+              },
+              [&](const TNode &n) -> bool { return goal == n; });
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TGraph, typename TNode, typename F1, typename F2>
+ext::vector<TNode> DFS::impl(const TGraph &graph,
+                             const TNode &start,
+                             const TNode &goal,
+                             F1 f_user,
+                             F2 f_stop) {
+  Data<TNode> data;
+
+  // Init search
+  data.d[start] = -1;
+
+  // Start DFS
+  expansion(graph, data, start, start, f_user, f_stop);
+
+  return common::ReconstructPath::reconstructPath(data.p, start, goal);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TGraph, typename TNode, typename F1, typename F2>
+bool
+DFS::expansion(const TGraph &graph,
+               DFS::Data<TNode> &data,
+               const TNode &n,
+               const TNode &p,
+               F1 f_user,
+               F2 f_stop) {
+  if (data.v.find(n) != data.v.end()) return false;
+
+  data.v.insert(n);
+  data.p.insert_or_assign(n, p);
+  data.d[n] = data.d[p] + 1;
+
+  // Run user's function
+  if (f_user(n, data.d[n])) {
+    return true; // Stop algorithm
+  }
+
+  // Stop if reach the goal
+  if (f_stop(n)) {
+    return true; // Stop algorithm
+  }
+
+  for (const auto &i : graph.successors(n)) {
+    bool stop = expansion(graph, data, i, n, f_user, f_stop);
+
+    if (stop) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+// =====================================================================================================================
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+} // namespace traverse
+#endif //ALIB2_DFS_HPP
-- 
GitLab