diff --git a/alib2graph_algo/src/common/ReconstructPath.hpp b/alib2graph_algo/src/common/ReconstructPath.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b15ffedf76b709ee225f22fb7c4171a81b79330b
--- /dev/null
+++ b/alib2graph_algo/src/common/ReconstructPath.hpp
@@ -0,0 +1,177 @@
+// ReconstructPath.hpp
+//
+//     Created on: 19. 12. 2017
+//         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_RECONSTRUCTPATH_HPP
+#define ALIB2_RECONSTRUCTPATH_HPP
+
+#include <alib/map>
+#include <alib/vector>
+#include <algorithm>
+
+namespace common {
+
+class ReconstructPath {
+// ---------------------------------------------------------------------------------------------------------------------
+ public:
+  template<typename TNode>
+  static ext::vector<TNode> reconstructPath(const ext::map<TNode, TNode> &p,
+                                            const TNode &start,
+                                            const TNode &goal);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TNode>
+  static ext::vector<TNode> reconstructPath(const ext::map<TNode, TNode> &p_forward,
+                                            const ext::map<TNode, TNode> &p_backward,
+                                            const TNode &start,
+                                            const TNode &goal,
+                                            const TNode &intersection_node);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TNode, typename TWeight>
+  static
+  ext::pair<ext::vector<TNode>, TWeight>
+  reconstructWeightedPath(const ext::map<TNode, TNode> &p,
+                          const ext::map<TNode, TWeight> &g,
+                          const TNode &start,
+                          const TNode &goal);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TNode, typename TWeight>
+  static
+  ext::pair<ext::vector<TNode>, TWeight>
+  reconstructWeightedPath(const ext::map<TNode, TNode> &p_forward,
+                          const ext::map<TNode, TNode> &p_backward,
+                          const ext::map<TNode, TWeight> &g_forward,
+                          const ext::map<TNode, TWeight> &g_backward,
+                          const TNode &start,
+                          const TNode &goal,
+                          const TNode &intersection_node);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TNode>
+  static
+  ext::vector<TNode>
+  joinPath(ext::vector<TNode> &forward_path, const ext::vector<TNode> &backward_path);
+
+// ---------------------------------------------------------------------------------------------------------------------
+};
+// =====================================================================================================================
+
+template<typename TNode>
+ext::vector<TNode> ReconstructPath::reconstructPath(const ext::map<TNode, TNode> &p,
+                                                    const TNode &start,
+                                                    const TNode &goal) {
+  ext::vector<TNode> path;
+
+  // Path not found -> return empty vector
+  if (p.find(goal) == p.end()) {
+    return path;
+  }
+
+  path.push_back(goal);
+  TNode current_vertex = goal;
+
+  while (current_vertex != start) {
+    current_vertex = p.at(current_vertex);
+    path.push_back(current_vertex);
+  }
+
+  // Path need to be reverse.
+  std::reverse(path.begin(), path.end());
+
+  return path;
+}
+
+template<typename TNode>
+ext::vector<TNode> ReconstructPath::reconstructPath(const ext::map<TNode, TNode> &p_forward,
+                                                    const ext::map<TNode, TNode> &p_backward,
+                                                    const TNode &start,
+                                                    const TNode &goal,
+                                                    const TNode &intersection_node) {
+  ext::vector<TNode> path;
+
+  // Path not found -> return empty vector
+  if (p_forward.find(intersection_node) == p_forward.end()
+      || p_backward.find(intersection_node) == p_backward.end()) {
+    return path;
+  }
+
+  // First part of the path. From start to intersectionVertex (include).
+  path.push_back(intersection_node);
+  TNode current_vertex = intersection_node;
+
+  while (current_vertex != start) {
+    current_vertex = p_forward.at(current_vertex);
+    path.push_back(current_vertex);
+  }
+  // This part of the path need to be reverse.
+  std::reverse(path.begin(), path.end());
+
+  // Second part of the path. From intersectionVertex (exclude) to goal.
+  current_vertex = intersection_node;
+  while (current_vertex != goal) {
+    current_vertex = p_backward.at(current_vertex);
+    path.push_back(current_vertex);
+  }
+  // No reverse at the end.
+
+  return path;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TNode, typename TWeight>
+ext::pair<ext::vector<TNode>, TWeight>
+ReconstructPath::reconstructWeightedPath(const ext::map<TNode, TNode> &p,
+                                         const ext::map<TNode, TWeight> &g,
+                                         const TNode &start,
+                                         const TNode &goal) {
+  if (g.find(goal) == g.end()) {
+    return ext::make_pair(ext::vector<TNode>(), std::numeric_limits<TWeight>::max());
+  }
+
+  return ext::make_pair(reconstructPath(p, start, goal), g.at(goal));
+}
+
+template<typename TNode, typename TWeight>
+ext::pair<ext::vector<TNode>, TWeight>
+ReconstructPath::reconstructWeightedPath(const ext::map<TNode, TNode> &p_forward,
+                                         const ext::map<TNode, TNode> &p_backward,
+                                         const ext::map<TNode, TWeight> &g_forward,
+                                         const ext::map<TNode, TWeight> &g_backward,
+                                         const TNode &start,
+                                         const TNode &goal,
+                                         const TNode &intersection_node) {
+  if (g_forward.find(intersection_node) == g_forward.end() || g_backward.find(intersection_node) == g_backward.end()) {
+    return ext::make_pair(ext::vector<TNode>(), std::numeric_limits<TWeight>::max());
+  }
+
+  return ext::make_pair(reconstructPath(p_forward, p_backward, start, goal, intersection_node),
+                        g_forward.at(intersection_node) + g_backward.at(intersection_node));
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TNode>
+ext::vector<TNode> ReconstructPath::joinPath(ext::vector<TNode> &forward_path,
+                                             const ext::vector<TNode> &backward_path) {
+  // ++ because we want skip the insertion node -> already in forward_path
+  forward_path.insert(forward_path.end(), ++backward_path.rbegin(), backward_path.rend());
+  return forward_path;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+} // namespace common
+
+#endif //ALIB2_RECONSTRUCTPATH_HPP
diff --git a/alib2graph_algo/src/traverse/BFS.cpp b/alib2graph_algo/src/traverse/BFS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6d349461a25e0e98b6e7b6e0c18b5863f4fb26e0
--- /dev/null
+++ b/alib2graph_algo/src/traverse/BFS.cpp
@@ -0,0 +1,228 @@
+// BFS.cpp
+//
+// Created on: 08. 12. 2017
+// 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 "BFS.hpp"
+
+#include <registration/AlgoRegistration.hpp>
+#include <graph/GraphClasses.hpp>
+#include <grid/GridClasses.hpp>
+
+namespace traverse {
+class BFSBidirectional {};
+}
+
+namespace {
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Normal Graph uni-directional
+
+auto BFS1 = registration::AbstractRegister<traverse::BFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::UndirectedGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto BFS2 = registration::AbstractRegister<traverse::BFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::UndirectedMultiGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto BFS3 = registration::AbstractRegister<traverse::BFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::DirectedGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto BFS4 = registration::AbstractRegister<traverse::BFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::DirectedMultiGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto BFS5 = registration::AbstractRegister<traverse::BFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::MixedGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto BFS6 = registration::AbstractRegister<traverse::BFS,
+                                           ext::vector<DefaultNodeType>,
+                                           const graph::MixedMultiGraph<> &,
+                                           const DefaultNodeType &,
+                                           const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto BFSGrid1 = registration::AbstractRegister<traverse::BFS,
+                                               ext::vector<DefaultSquareGridNodeType>,
+                                               const grid::SquareGrid4<> &,
+                                               const DefaultSquareGridNodeType &,
+                                               const DefaultSquareGridNodeType &>(traverse::BFS::findPathRegistration);
+
+auto BFSGrid2 = registration::AbstractRegister<traverse::BFS,
+                                               ext::vector<DefaultSquareGridNodeType>,
+                                               const grid::SquareGrid8<> &,
+                                               const DefaultSquareGridNodeType &,
+                                               const DefaultSquareGridNodeType &>(traverse::BFS::findPathRegistration);
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Normal Graph bidirectional
+
+auto BFSBidirectional1 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                        ext::vector<DefaultNodeType>,
+                                                        const graph::UndirectedGraph<> &,
+                                                        const DefaultNodeType &,
+                                                        const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto BFSBidirectional2 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                        ext::vector<DefaultNodeType>,
+                                                        const graph::UndirectedMultiGraph<> &,
+                                                        const DefaultNodeType &,
+                                                        const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto BFSBidirectional3 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                        ext::vector<DefaultNodeType>,
+                                                        const graph::DirectedGraph<> &,
+                                                        const DefaultNodeType &,
+                                                        const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto BFSBidirectional4 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                        ext::vector<DefaultNodeType>,
+                                                        const graph::DirectedMultiGraph<> &,
+                                                        const DefaultNodeType &,
+                                                        const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto BFSBidirectional5 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                        ext::vector<DefaultNodeType>,
+                                                        const graph::MixedGraph<> &,
+                                                        const DefaultNodeType &,
+                                                        const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto BFSBidirectional6 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                        ext::vector<DefaultNodeType>,
+                                                        const graph::MixedMultiGraph<> &,
+                                                        const DefaultNodeType &,
+                                                        const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto BFSGridBidirectional1 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                            ext::vector<DefaultSquareGridNodeType>,
+                                                            const grid::SquareGrid4<> &,
+                                                            const DefaultSquareGridNodeType &,
+                                                            const DefaultSquareGridNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto BFSGridbidirectional2 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                            ext::vector<DefaultSquareGridNodeType>,
+                                                            const grid::SquareGrid8<> &,
+                                                            const DefaultSquareGridNodeType &,
+                                                            const DefaultSquareGridNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Weighted Graph uni-directional
+
+auto WBFS1 = registration::AbstractRegister<traverse::BFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedUndirectedGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto WBFS2 = registration::AbstractRegister<traverse::BFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedUndirectedMultiGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto WBFS3 = registration::AbstractRegister<traverse::BFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedDirectedGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto WBFS4 = registration::AbstractRegister<traverse::BFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedDirectedMultiGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto WBFS5 = registration::AbstractRegister<traverse::BFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedMixedGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto WBFS6 = registration::AbstractRegister<traverse::BFS,
+                                            ext::vector<DefaultNodeType>,
+                                            const graph::WeightedMixedMultiGraph<> &,
+                                            const DefaultNodeType &,
+                                            const DefaultNodeType &>(traverse::BFS::findPathRegistration);
+
+auto WBFSGrid1 = registration::AbstractRegister<traverse::BFS,
+                                                ext::vector<DefaultSquareGridNodeType>,
+                                                const grid::WeightedSquareGrid4<> &,
+                                                const DefaultSquareGridNodeType &,
+                                                const DefaultSquareGridNodeType &>(traverse::BFS::findPathRegistration);
+
+auto WBFSGrid2 = registration::AbstractRegister<traverse::BFS,
+                                                ext::vector<DefaultSquareGridNodeType>,
+                                                const grid::WeightedSquareGrid8<> &,
+                                                const DefaultSquareGridNodeType &,
+                                                const DefaultSquareGridNodeType &>(traverse::BFS::findPathRegistration);
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Weighted Graph bidirectional
+
+auto WBFSBidirectional1 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                         ext::vector<DefaultNodeType>,
+                                                         const graph::WeightedUndirectedGraph<> &,
+                                                         const DefaultNodeType &,
+                                                         const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto WBFSBidirectional2 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                         ext::vector<DefaultNodeType>,
+                                                         const graph::WeightedUndirectedMultiGraph<> &,
+                                                         const DefaultNodeType &,
+                                                         const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto WBFSBidirectional3 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                         ext::vector<DefaultNodeType>,
+                                                         const graph::WeightedDirectedGraph<> &,
+                                                         const DefaultNodeType &,
+                                                         const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto WBFSBidirectional4 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                         ext::vector<DefaultNodeType>,
+                                                         const graph::WeightedDirectedMultiGraph<> &,
+                                                         const DefaultNodeType &,
+                                                         const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto WBFSBidirectional5 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                         ext::vector<DefaultNodeType>,
+                                                         const graph::WeightedMixedGraph<> &,
+                                                         const DefaultNodeType &,
+                                                         const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto WBFSBidirectional6 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                         ext::vector<DefaultNodeType>,
+                                                         const graph::WeightedMixedMultiGraph<> &,
+                                                         const DefaultNodeType &,
+                                                         const DefaultNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto WBFSGridBidirectional1 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                             ext::vector<DefaultSquareGridNodeType>,
+                                                             const grid::WeightedSquareGrid4<> &,
+                                                             const DefaultSquareGridNodeType &,
+                                                             const DefaultSquareGridNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+auto WBFSGridbidirectional2 = registration::AbstractRegister<traverse::BFSBidirectional,
+                                                             ext::vector<DefaultSquareGridNodeType>,
+                                                             const grid::WeightedSquareGrid8<> &,
+                                                             const DefaultSquareGridNodeType &,
+                                                             const DefaultSquareGridNodeType &>(traverse::BFS::findPathBidirectionalRegistration);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+}
diff --git a/alib2graph_algo/src/traverse/BFS.hpp b/alib2graph_algo/src/traverse/BFS.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c88b81034c5086844cfc27eb32e6bf0df9b4a7f4
--- /dev/null
+++ b/alib2graph_algo/src/traverse/BFS.hpp
@@ -0,0 +1,339 @@
+// BFS.hpp
+//
+//     Created on: 13. 11. 2017
+//         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_BFS_HPP
+#define ALIB2_BFS_HPP
+
+#include <functional>
+#include <queue>
+#include <alib/map>
+#include <alib/set>
+#include <iostream>
+
+#include <common/ReconstructPath.hpp>
+
+namespace traverse {
+
+class BFS {
+// ---------------------------------------------------------------------------------------------------------------------
+
+ public:
+
+  /// Run BFS 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<void(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 the shortest path using BFS algorithm from the \p start node to the \p goal 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).
+  ///
+  /// \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 shortest 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);
+
+  }
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  /// Find the shortest path using BFS algorithm from the \p start node to the \p goal node in the \p graph.
+  /// This algorithm is run in both direction, from \p start and also from \p goal.
+  ///
+  /// 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 shortest 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>
+  findPathBidirectional(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>
+  findPathBidirectionalRegistration(const TGraph &graph,
+                                    const TNode &start,
+                                    const TNode &goal) {
+    return findPath(graph, start, goal);
+  }
+
+// =====================================================================================================================
+
+ private:
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TNode>
+  struct Data {
+    std::queue<TNode> queue;
+    ext::set<TNode> v;
+    ext::map<TNode, TNode> p;
+    ext::map<TNode, size_t> d;
+  };
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TGraph, typename TNode, typename F1, typename F2>
+  static
+  ext::vector<TNode>
+  implNormal(const TGraph &graph,
+             const TNode &start,
+             const TNode &goal,
+             F1 f_user,
+             F2 f_stop);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename FSucc, typename TNode, typename F1, typename F2>
+  static bool expansion(FSucc successors,
+                        Data<TNode> &data,
+                        F1 f_user,
+                        F2 f_stop);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TGraph, typename TNode, typename F1>
+  static
+  ext::vector<TNode>
+  implBidirectional(const TGraph &graph,
+                    const TNode &start,
+                    const TNode &goal,
+                    F1 f_user);
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TNode>
+  inline static void init(BFS::Data<TNode> &data, const TNode &start);
+
+// ---------------------------------------------------------------------------------------------------------------------
+};
+
+// =====================================================================================================================
+
+template<typename TGraph, typename TNode, typename F>
+void BFS::run(const TGraph &graph, const TNode &start, F f_user) {
+  // goal -> start: in order to avoid call constructor
+  implNormal(graph, start, start, f_user, [](const TNode &) -> bool { return false; });
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TGraph, typename TNode, typename F>
+ext::vector<TNode>
+BFS::findPath(const TGraph &graph,
+              const TNode &start,
+              const TNode &goal,
+              F f_user) {
+  return implNormal(graph, start, goal,
+                    [&](const TNode &n, const size_t &d) -> bool {
+                      f_user(n, d);
+                      return false;
+                    },
+                    [&goal](const TNode &n) -> bool { return goal == n; });
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TGraph, typename TNode, typename F>
+ext::vector<TNode>
+BFS::findPathBidirectional(const TGraph &graph,
+                           const TNode &start,
+                           const TNode &goal,
+                           F f_user) {
+  return implBidirectional(graph, start, goal,
+                           [&](const TNode &n, const size_t &d) -> bool {
+                             f_user(n, d);
+                             return false;
+                           });
+}
+
+// =====================================================================================================================
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TGraph, typename TNode, typename F1, typename F2>
+ext::vector<TNode>
+BFS::implNormal(const TGraph &graph,
+                const TNode &start,
+                const TNode &goal,
+                F1 f_user,
+                F2 f_stop) {
+  Data<TNode> data;
+
+  // Init search
+  init(data, start);
+
+  while (!data.queue.empty()) {
+    bool stop = expansion([&](const TNode &node) { return graph.successors(node); }, data, f_user, f_stop);
+
+    if (stop) {
+      break;
+    }
+
+  }
+
+  return common::ReconstructPath::reconstructPath(data.p, start, goal);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename FSucc, typename TNode, typename F1, typename F2>
+bool BFS::expansion(FSucc successors,
+                    Data<TNode> &data,
+                    F1 f_user,
+                    F2 f_stop) {
+  TNode n = data.queue.front();
+  data.queue.pop();
+
+  // Run user's function
+  if (f_user(n, data.d[n])) {
+    return true;
+  }
+
+  // Stop if reach the goal
+  if (f_stop(n)) {
+    return true;
+  }
+
+  for (const auto &s : successors(n)) {
+    if (data.v.count(s) == 0) {
+      data.v.insert(s);
+      data.p.insert_or_assign(s, n);
+      data.queue.push(s);
+    }
+  }
+
+  return false;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TGraph, typename TNode, typename F1>
+ext::vector<TNode>
+BFS::implBidirectional(const TGraph &graph,
+                       const TNode &start,
+                       const TNode &goal,
+                       F1 f_user) {
+  Data<TNode> forward_data, backward_data;
+  ext::vector<TNode> intersection;
+
+  // Init forward search
+  init(forward_data, start);
+
+  // Init backward search
+  init(backward_data, goal);
+
+  while (!forward_data.queue.empty() && !backward_data.queue.empty()) {
+    // Forward search relaxation
+    bool stop = expansion([&](const TNode &node) { return graph.successors(node); }, forward_data, f_user,
+                          [&](const TNode &n) {
+                            if (backward_data.v.find(n) != backward_data.v.end()) {
+                              intersection.push_back(n);
+                              return true;
+                            }
+                            return false;
+                          });
+
+
+    // If there is a intersection, then we can reconstruct path
+    if (stop) {
+      return common::ReconstructPath::reconstructPath(forward_data.p,
+                                                      backward_data.p,
+                                                      start,
+                                                      goal,
+                                                      *intersection.begin());
+    }
+
+    // Backward search relaxation
+    stop = expansion([&](const TNode &node) { return graph.predecessors(node); }, backward_data, f_user,
+                     [&](const TNode &n) {
+                       if (forward_data.v.find(n) != forward_data.v.end()) {
+                         intersection.push_back(n);
+                         return true;
+                       }
+                       return false;
+                     });
+
+    // If there is a intersection, then we can reconstruct path
+    if (stop) {
+      return common::ReconstructPath::reconstructPath(forward_data.p,
+                                                      backward_data.p,
+                                                      start,
+                                                      goal,
+                                                      *intersection.begin());
+    }
+  }
+
+  // Path not found -> return empty vector
+  return ext::vector<TNode>();
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TNode>
+void BFS::init(BFS::Data<TNode> &data, const TNode &start) {
+  data.queue.push(start);
+  data.v.insert(start);
+  data.p.insert_or_assign(start, start);
+  data.d[start] = 0;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+} // namespace traverse
+#endif // ALIB2_BFS_HPP