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