diff --git a/alib2graph_algo/src/traverse/IDDFS.cpp b/alib2graph_algo/src/traverse/IDDFS.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d827cc485f0485f95936237adf4842608104c759 --- /dev/null +++ b/alib2graph_algo/src/traverse/IDDFS.cpp @@ -0,0 +1,228 @@ +// IDDFS.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 "IDDFS.hpp" + +#include <registration/AlgoRegistration.hpp> +#include <graph/GraphClasses.hpp> +#include <grid/GridClasses.hpp> + +namespace traverse { +class IDDFSBidirectional {}; +} + +namespace { + +// --------------------------------------------------------------------------------------------------------------------- +// Normal Graph uni-directional + +auto IDDFS1 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::UndirectedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto IDDFS2 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::UndirectedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto IDDFS3 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::DirectedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto IDDFS4 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::DirectedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto IDDFS5 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::MixedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto IDDFS6 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::MixedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto IDDFSGrid1 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultSquareGridNodeType>, + const grid::SquareGrid4<> &, + const DefaultSquareGridNodeType &, + const DefaultSquareGridNodeType &>(traverse::IDDFS::findPathRegistration); + +auto IDDFSGrid2 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultSquareGridNodeType>, + const grid::SquareGrid8<> &, + const DefaultSquareGridNodeType &, + const DefaultSquareGridNodeType &>(traverse::IDDFS::findPathRegistration); + +// --------------------------------------------------------------------------------------------------------------------- +// Normal Graph bidirectional + +auto IDDFSBidirectional1 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::UndirectedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto IDDFSBidirectional2 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::UndirectedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto IDDFSBidirectional3 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::DirectedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto IDDFSBidirectional4 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::DirectedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto IDDFSBidirectional5 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::MixedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto IDDFSBidirectional6 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::MixedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto IDDFSGridBidirectional1 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultSquareGridNodeType>, + const grid::SquareGrid4<> &, + const DefaultSquareGridNodeType &, + const DefaultSquareGridNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto IDDFSGridbidirectional2 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultSquareGridNodeType>, + const grid::SquareGrid8<> &, + const DefaultSquareGridNodeType &, + const DefaultSquareGridNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +// --------------------------------------------------------------------------------------------------------------------- +// Weighted Graph uni-directional + +auto WIDDFS1 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::WeightedUndirectedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto WIDDFS2 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::WeightedUndirectedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto WIDDFS3 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::WeightedDirectedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto WIDDFS4 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::WeightedDirectedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto WIDDFS5 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::WeightedMixedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto WIDDFS6 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultNodeType>, + const graph::WeightedMixedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathRegistration); + +auto WIDDFSGrid1 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultSquareGridNodeType>, + const grid::WeightedSquareGrid4<> &, + const DefaultSquareGridNodeType &, + const DefaultSquareGridNodeType &>(traverse::IDDFS::findPathRegistration); + +auto WIDDFSGrid2 = registration::AbstractRegister<traverse::IDDFS, + ext::vector<DefaultSquareGridNodeType>, + const grid::WeightedSquareGrid8<> &, + const DefaultSquareGridNodeType &, + const DefaultSquareGridNodeType &>(traverse::IDDFS::findPathRegistration); + +// --------------------------------------------------------------------------------------------------------------------- +// Weighted Graph bidirectional + +auto WIDDFSBidirectional1 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::WeightedUndirectedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto WIDDFSBidirectional2 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::WeightedUndirectedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto WIDDFSBidirectional3 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::WeightedDirectedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto WIDDFSBidirectional4 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::WeightedDirectedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto WIDDFSBidirectional5 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::WeightedMixedGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto WIDDFSBidirectional6 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultNodeType>, + const graph::WeightedMixedMultiGraph<> &, + const DefaultNodeType &, + const DefaultNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto WIDDFSGridBidirectional1 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultSquareGridNodeType>, + const grid::WeightedSquareGrid4<> &, + const DefaultSquareGridNodeType &, + const DefaultSquareGridNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +auto WIDDFSGridbidirectional2 = registration::AbstractRegister<traverse::IDDFSBidirectional, + ext::vector<DefaultSquareGridNodeType>, + const grid::WeightedSquareGrid8<> &, + const DefaultSquareGridNodeType &, + const DefaultSquareGridNodeType &>(traverse::IDDFS::findPathBidirectionalRegistration); + +// --------------------------------------------------------------------------------------------------------------------- + +} diff --git a/alib2graph_algo/src/traverse/IDDFS.hpp b/alib2graph_algo/src/traverse/IDDFS.hpp new file mode 100644 index 0000000000000000000000000000000000000000..36b32e8653f48180f6964bdf936da10997ff8c19 --- /dev/null +++ b/alib2graph_algo/src/traverse/IDDFS.hpp @@ -0,0 +1,456 @@ +// IDIDDFS.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_IDIDDFS_HPP +#define ALIB2_IDIDDFS_HPP + +#include <functional> +#include <alib/vector> +#include <queue> +#include <limits> +#include <alib/set> +#include <alib/map> + +#include <common/ReconstructPath.hpp> + +namespace traverse { + +class IDDFS { +// --------------------------------------------------------------------------------------------------------------------- + + public: + + /// Run IDDFS algorithm from the \p start node in the \p graph. + /// Be aware that running this algorithm on a non-tree graph gonna be extremely slow. + /// + /// 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 max_depth set maximal allowed depth for IDDFS. + /// \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, + unsigned long max_depth = std::numeric_limits<unsigned long>::max(), + F f_user = [](const TNode &, const size_t &) -> bool { return false; }); + +// --------------------------------------------------------------------------------------------------------------------- + + /// Find the shortest path using IDDFS algorithm from the \p start node to the \p goal node in the \p graph. + /// Be aware that running this algorithm on a non-tree graph gonna be extremely slow. + /// + /// 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 max_depth set maximal allowed depth for IDDFS. + /// \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, + unsigned long max_depth = std::numeric_limits<unsigned long>::max(), + 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 IDDFS 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. + /// Be aware that running this algorithm on a non-tree graph gonna be extremely slow. + /// + /// 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 max_depth set maximal allowed depth for IDDFS. + /// \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, + unsigned long max_depth = std::numeric_limits<unsigned long>::max(), + 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 { + ext::vector<TNode> path; // current path + ext::set<TNode> path_set; // current path set for quick search + ext::set<TNode> v; // visited + }; + +// --------------------------------------------------------------------------------------------------------------------- + + template<typename TGraph, typename TNode, typename F1, typename F2> + static + ext::vector<TNode> + implNormal(const TGraph &graph, + const TNode &start, + unsigned long max_depth, + F1 f_user, + F2 f_stop); + +// --------------------------------------------------------------------------------------------------------------------- + + template<typename FSucc, typename TNode, typename F1, typename F2> + static + bool + expansion(FSucc successors, + IDDFS::Data<TNode> &data, + const TNode &n, + bool save_nodes, + unsigned long max_depth, + F1 f_user, + F2 f_stop); + +// --------------------------------------------------------------------------------------------------------------------- + + template<typename TGraph, typename TNode, typename F1, typename F2> + static + ext::vector<TNode> + implBidirectional(const TGraph &graph, + const TNode &start, + const TNode &goal, + unsigned long max_depth, + F1 f_user, + F2 f_stop); + +// --------------------------------------------------------------------------------------------------------------------- + + template<typename FSucc, typename TNode, typename F1, typename F2> + static + ext::set<TNode> + backward_expansion(FSucc successors, + const IDDFS::Data<TNode> &forward_data, + IDDFS::Data<TNode> &backward_data, + const TNode &node, + unsigned long max_depth, + F1 f_user, + F2 f_stop); + +// --------------------------------------------------------------------------------------------------------------------- + + template<typename TGraph, typename TNode> + static + ext::vector<TNode> + constructPath(const TGraph &graph, + const TNode &start, + const TNode &goal, + TNode intersection, + unsigned long max_forward_depth, + unsigned long max_backward_depth); + +// --------------------------------------------------------------------------------------------------------------------- + + template<typename TNode> + inline static void init(IDDFS::Data<TNode> &data, const TNode &start); + +// --------------------------------------------------------------------------------------------------------------------- + +}; + +// ===================================================================================================================== + +template<typename TGraph, typename TNode, typename F> +void IDDFS::run(const TGraph &graph, const TNode &start, unsigned long max_depth, F f_user) { + implNormal(graph, start, max_depth, f_user, [](const TNode &) -> bool { return false; }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +template<typename TGraph, typename TNode, typename F> +ext::vector<TNode> IDDFS::findPath(const TGraph &graph, + const TNode &start, + const TNode &goal, + unsigned long max_depth, + F f_user) { + return implNormal(graph, start, max_depth, + [&](const TNode &n, const auto &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> IDDFS::findPathBidirectional(const TGraph &graph, + const TNode &start, + const TNode &goal, + unsigned long max_depth, + F f_user) { + return implBidirectional(graph, start, goal, max_depth, + [&](const TNode &n, const auto &d) -> bool { + f_user(n, d); + return false; + }, + [](const TNode &) -> bool { return false; }); +} + +// ===================================================================================================================== + +// --------------------------------------------------------------------------------------------------------------------- + +template<typename TGraph, typename TNode, typename F1, typename F2> +ext::vector<TNode> IDDFS::implNormal(const TGraph &graph, + const TNode &start, + unsigned long max_depth, + F1 f_user, + F2 f_stop) { + for (unsigned long i = 1; i < max_depth; ++i) { + Data<TNode> data; + + // Init search + init(data, start); + + bool stop = + expansion([&](const TNode &node) { return graph.successors(node); }, data, start, false, i, f_user, f_stop); + + if (stop) { + return data.path; + } + } + + return ext::vector<TNode>(); +} + +// --------------------------------------------------------------------------------------------------------------------- + +template<typename FSucc, typename TNode, typename F1, typename F2> +bool IDDFS::expansion(FSucc successors, + IDDFS::Data<TNode> &data, + const TNode &n, + bool save_nodes, + unsigned long max_depth, + F1 f_user, + F2 f_stop) { + if (max_depth == 0) return false; // Continue with search + else if (save_nodes && max_depth == 1) { + data.v.insert(n); // Remember only the deepest nodes + } + + // Run user's function + if (f_user(n, data.path.size())) { + return true; // Stop algorithm + } + + // Stop if reach the goal + if (f_stop(n)) { + return true; // Stop algorithm + } + + for (const auto &s : successors(n)) { + + // Check if node is not in path + if (data.path_set.find(s) != data.path_set.end()) { + continue; + } + + data.path.push_back(s); // Insert current node + data.path_set.insert(s); + bool stop = expansion(successors, data, s, save_nodes, max_depth - 1, f_user, f_stop); + + if (stop) { + return true; // Stop algorithm + } + + data.path.pop_back(); // Remove current node + data.path_set.erase(data.path_set.find(s)); + } + + return false; // Continue with search +} + +// --------------------------------------------------------------------------------------------------------------------- + +template<typename TGraph, typename TNode, typename F1, typename F2> +ext::vector<TNode> IDDFS::implBidirectional(const TGraph &graph, + const TNode &start, + const TNode &goal, + unsigned long max_depth, + F1 f_user, + F2 f_stop) { + for (unsigned long i = 1; i < max_depth; ++i) { + // ------------------------------- + // Forward search + Data<TNode> forward_data; + + // Init forward search + init(forward_data, start); + + expansion([&](const TNode &n) { return graph.successors(n); }, forward_data, start, true, i, f_user, f_stop); + + // ------------------------------- + // Backward search + + ext::set<TNode> intersection; + + Data<TNode> backward_data; + + // Init backward search + init(backward_data, goal); + + intersection = backward_expansion([&](const TNode &node) { return graph.predecessors(node); }, + forward_data, + backward_data, + goal, + i, + f_user, + f_stop); // even run + + // If there is a intersection, then we can construct path + if (intersection.size() != 0) { + return constructPath(graph, start, goal, *intersection.begin(), i, i); + } + + // Init backward search + init(backward_data, goal); + + intersection = backward_expansion([&](const TNode &node) { return graph.predecessors(node); }, + forward_data, + backward_data, + goal, + i + 1, + f_user, + f_stop); // odd run + + // If there is a intersection, then we can reconstruct path + if (intersection.size() != 0) { + return constructPath(graph, start, goal, *intersection.begin(), i, i + 1); + } + } + + return ext::vector<TNode>(); +} + +// --------------------------------------------------------------------------------------------------------------------- + +template<typename FSucc, typename TNode, typename F1, typename F2> +ext::set<TNode> IDDFS::backward_expansion(FSucc successors, + const IDDFS::Data<TNode> &forward_data, + IDDFS::Data<TNode> &backward_data, + const TNode &node, + unsigned long max_depth, + F1 f_user, + F2 f_stop) { + expansion(successors, backward_data, node, true, max_depth, f_user, f_stop); + + // Check for intersection + ext::set<TNode> intersection; + std::set_intersection(forward_data.v.begin(), forward_data.v.end(), + backward_data.v.begin(), backward_data.v.end(), + std::inserter(intersection, intersection.begin())); + + return intersection; +} + +// --------------------------------------------------------------------------------------------------------------------- + +template<typename TGraph, typename TNode> +ext::vector<TNode> IDDFS::constructPath(const TGraph &graph, + const TNode &start, + const TNode &goal, + TNode intersection, + unsigned long max_forward_depth, + unsigned long max_backward_depth) { + Data<TNode> forward_data, backward_data; + init(forward_data, start); + init(backward_data, goal); + + // Re-run forward search + expansion([&](const TNode &node) { return graph.successors(node); }, + forward_data, + start, + false, + max_forward_depth, + [](const TNode &, const size_t &) -> bool { return false; }, + [&](const TNode &n) -> bool { return n == intersection; } + ); + + // Re-run backward search + expansion([&](const TNode &node) { return graph.predecessors(node); }, + backward_data, + goal, + false, + max_backward_depth, + [](const TNode &, const size_t &) -> bool { return false; }, + [&](const TNode &n) -> bool { return n == intersection; } + ); + + return common::ReconstructPath::joinPath(forward_data.path, backward_data.path); +} + +// --------------------------------------------------------------------------------------------------------------------- + +template<typename TNode> +void IDDFS::init(IDDFS::Data<TNode> &data, const TNode &start) { + // Make sure that data are wiped + data.path.clear(); + data.v.clear(); + + data.path.push_back(start); + data.path_set.insert(start); +} + +// --------------------------------------------------------------------------------------------------------------------- + +} // namespace traverse +#endif //ALIB2_IDIDDFS_HPP