Skip to content

Commit

Permalink
feat: graph::bfs namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
DNKpp committed Oct 1, 2023
1 parent 653eb34 commit 483f287
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 0 deletions.
38 changes: 38 additions & 0 deletions include/Simple-Utility/graph/BreadthFirstSearch.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright Dominic Koepke 2019 - 2023.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)

#ifndef SIMPLE_UTILITY_GRAPH_BREADTH_FIRST_SEARCH_HPP
#define SIMPLE_UTILITY_GRAPH_BREADTH_FIRST_SEARCH_HPP

#pragma once

#include "Simple-Utility/graph/Traverse.hpp"
#include "Simple-Utility/graph/mixins/queue/std_queue.hpp"
#include "Simple-Utility/graph/mixins/tracker/std_unordered_map.hpp"

namespace sl::graph::dfs
{
template <concepts::basic_node Node>
struct NodeFactory
: public detail::NodeFactory<Node>
{
};

template <
class View,
concepts::basic_node Node = CommonBasicNode<edge::vertex_t<view::edge_t<View>>>,
concepts::tracker_for<node::vertex_t<Node>> Tracker = tracker::CommonHashMap<node::vertex_t<Node>>>
requires concepts::view_for<View, Node>
&& (!concepts::ranked_node<Node>)
using Range = IterableTraverser<
detail::BasicTraverser<
Node,
View,
queue::CommonQueue<Node>,
Tracker,
detail::default_kernel_t<Node, NodeFactory<Node>>>>;
}

#endif
100 changes: 100 additions & 0 deletions tests/graph/BreadthFirstSearch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright Dominic Koepke 2019 - 2023.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)

#include "Simple-Utility/graph/BreadthFirstSearch.hpp"

#include <catch2/catch_template_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/matchers/catch_matchers_range_equals.hpp>

#include "Defines.hpp"

TEMPLATE_TEST_CASE(
"bfs::Range visits all reachable vertices.",
"[graph][graph::bfs]",
BasicViewStub,
WeightedViewStub
)
{
using Node = sg::CommonBasicNode<std::string>;
const auto& [expected, origin] = GENERATE(
(table<std::vector<Node>, std::string>)({
{{{"3"}, {"5"}, {"6"}, {"2"}}, "3"},
{{{"6"}, {"2"}}, "6"},
{{{"1"}, {"2"}, {"3"}, {"6"}, {"5"}}, "1"},
{{{"8"}, {"7"}, {"9"}, {"4"}}, "8"}
}));

sg::dfs::Range<TestType, Node> range{origin, std::tuple{TestType{}}, std::tuple{}, std::tuple{}, std::tuple{}, std::tuple{}};
STATIC_CHECK(std::ranges::input_range<decltype(range)>);

REQUIRE_THAT(buffer_nodes(range), Catch::Matchers::RangeEquals(expected));
}

TEMPLATE_TEST_CASE(
"bfs::Range can be used with depth decorated nodes.",
"[graph][graph::bfs]",
BasicViewStub,
WeightedViewStub
)
{
using Node = sg::DepthNodeDecorator<sg::CommonBasicNode<std::string>>;
const auto& [expected, origin] = GENERATE(
(table<std::vector<Node>, std::string>)({
{{{{"3"}, 0}, {{"5"}, 1}, {{"6"}, 1}, {{"2"}, 2}}, "3"},
{{{{"6"}, 0}, {{"2"}, 1}}, "6"},
{{{{"1"}, 0}, {{"2"}, 1}, {{"3"}, 1}, {{"6"}, 2}, {{"5"}, 2}}, "1"},
{{{{"8"}, 0}, {{"7"}, 1}, {{"9"}, 1}, {{"4"}, 2}}, "8"}
}));

sg::dfs::Range<TestType, Node> range{origin, std::tuple{TestType{}}, std::tuple{}, std::tuple{}, std::tuple{}, std::tuple{}};
STATIC_CHECK(std::ranges::input_range<decltype(range)>);

REQUIRE_THAT(buffer_nodes(range), Catch::Matchers::RangeEquals(expected));
}

TEMPLATE_TEST_CASE(
"bfs::Range can be used with predecessor decorated nodes.",
"[graph][graph::bfs]",
BasicViewStub,
WeightedViewStub
)
{
using Node = sg::PredecessorNodeDecorator<sg::CommonBasicNode<std::string>>;
const auto& [expected, origin] = GENERATE(
(table<std::vector<Node>, std::string>)({
{{{{"3"}, std::nullopt}, {{"5"}, "3"}, {{"6"}, "3"}, {{"2"}, "6"}}, "3"},
{{{{"6"}, std::nullopt}, {{"2"}, "6"}}, "6"},
{{{{"1"}, std::nullopt}, {{"2"}, "1"}, {{"3"}, "1"}, {{"6"}, "2"}, {{"5"}, "3"}}, "1"},
{{{{"8"}, std::nullopt}, {{"7"}, "8"}, {{"9"}, "8"}, {{"4"}, "7"}}, "8"}
}));

sg::dfs::Range<TestType, Node> range{origin, std::tuple{TestType{}}, std::tuple{}, std::tuple{}, std::tuple{}, std::tuple{}};
STATIC_CHECK(std::ranges::input_range<decltype(range)>);

REQUIRE_THAT(buffer_nodes(range), Catch::Matchers::RangeEquals(expected));
}

TEMPLATE_TEST_CASE(
"bfs::Range can be used with arbitrary decorated nodes.",
"[graph][graph::bfs]",
BasicViewStub,
WeightedViewStub
)
{
using Node = sg::DepthNodeDecorator<sg::PredecessorNodeDecorator<sg::CommonBasicNode<std::string>>>;
const auto& [expected, origin] = GENERATE(
(table<std::vector<Node>, std::string>)({
{{{{{"3"}, std::nullopt}, 0}, {{{"5"}, "3"}, 1}, {{{"6"}, "3"}, 1}, {{{"2"}, "6"}, 2}}, "3"},
{{{{{"6"}, std::nullopt}, 0}, {{{"2"}, "6"}, 1}}, "6"},
{{{{{"1"}, std::nullopt}, 0}, {{{"2"}, "1"}, 1}, {{{"3"}, "1"}, 1}, {{{"6"}, "2"}, 2}, {{{"5"}, "3"}, 2}}, "1"},
{{{{{"8"}, std::nullopt}, 0}, {{{"7"}, "8"}, 1}, {{{"9"}, "8"}, 1}, {{{"4"}, "7"}, 2}}, "8"}
}));

sg::dfs::Range<TestType, Node> range{origin, std::tuple{TestType{}}, std::tuple{}, std::tuple{}, std::tuple{}, std::tuple{}};
STATIC_CHECK(std::ranges::input_range<decltype(range)>);

REQUIRE_THAT(buffer_nodes(range), Catch::Matchers::RangeEquals(expected));
}
1 change: 1 addition & 0 deletions tests/graph/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ target_sources(
Simple-Utility-Tests
PRIVATE
"AStarSearch.cpp"
"BreadthFirstSearch.cpp"
"Common.cpp"
"DepthFirstSearch.cpp"
"Edge.cpp"
Expand Down

0 comments on commit 483f287

Please sign in to comment.