Skip to content

Commit

Permalink
refactor: graph::view api and concepts
Browse files Browse the repository at this point in the history
  • Loading branch information
DNKpp committed Oct 9, 2023
1 parent 31dcbb8 commit 2c8b2e4
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 148 deletions.
8 changes: 5 additions & 3 deletions benchmarks/graph/AStarBoostComparison.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,19 +267,21 @@ template <>
struct sl::graph::view::traits<std::reference_wrapper<const maze>>
{
using edge_type = CommonWeightedEdge<vertex_descriptor, distance>;
using vertex_type = edge::vertex_t<edge_type>;
using weight_type = edge::weight_t<edge_type>;
};

template <>
struct sl::graph::customize::edges_fn<std::reference_wrapper<const maze>>
struct sl::graph::customize::out_edges_fn<std::reference_wrapper<const maze>>
{
using edge_type = view::edge_t<std::reference_wrapper<const maze>>;
using vertex_type = edge::vertex_t<edge_type>;
using weight_type = edge::weight_t<edge_type>;

constexpr auto operator ()(const maze& m, const auto& current) const
auto operator ()(const maze& m, const vertex_type& current) const
{
const auto& g = m.get_grid();
const auto [edgesBegin, edgesEnd] = out_edges(node::vertex(current), g);
const auto [edgesBegin, edgesEnd] = out_edges(current, g);

return ranges::subrange{edgesBegin, edgesEnd}
| ranges::views::transform([&](const auto& e) { return edge_type{target(e, g), 1.}; });
Expand Down
5 changes: 2 additions & 3 deletions include/Simple-Utility/graph/AStarSearch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,11 @@ namespace sl::graph::astar
};

template <
typename View,
concepts::basic_graph View,
typename Heuristic,
concepts::ranked_node Node = CommonNode<edge::vertex_t<view::edge_t<View>>, edge::weight_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::heuristic_for<Heuristic, Node>
requires concepts::heuristic_for<Heuristic, Node>
using Range = IterableTraverser<
graph::detail::BasicTraverser<
Node,
Expand Down
5 changes: 2 additions & 3 deletions include/Simple-Utility/graph/BreadthFirstSearch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ namespace sl::graph::dfs
using CommonNode = CommonBasicNode<Vertex>;

template <
class View,
concepts::basic_graph View,
concepts::basic_node Node = CommonNode<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>)
requires (!concepts::ranked_node<Node>)
using Range = IterableTraverser<
detail::BasicTraverser<
Node,
Expand Down
5 changes: 2 additions & 3 deletions include/Simple-Utility/graph/DepthFirstSearch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ namespace sl::graph::dfs
using CommonNode = CommonBasicNode<Vertex>;

template <
class View,
concepts::basic_graph View,
concepts::basic_node Node = CommonNode<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>)
requires (!concepts::ranked_node<Node>)
using Range = IterableTraverser<
detail::BasicTraverser<
Node,
Expand Down
15 changes: 8 additions & 7 deletions include/Simple-Utility/graph/Traverse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace sl::graph::concepts
{
template <typename T, typename Node, typename View, typename Tracker>
concept explorer = basic_node<Node>
&& view_for<View, Node>
&& basic_graph<View>
&& tracker_for<Tracker, node::vertex_t<Node>>
&& sl::concepts::unqualified<T>
&& std::destructible<T>
Expand All @@ -42,7 +42,8 @@ namespace sl::graph::concepts
};

template <typename T, typename View, typename Explorer, typename Queue, typename Tracker>
concept traverser_kernel = sl::concepts::unqualified<T>
concept traverser_kernel = basic_graph<View>
&& sl::concepts::unqualified<T>
&& std::destructible<T>
&& requires(
T& kernel,
Expand All @@ -53,9 +54,9 @@ namespace sl::graph::concepts
)
{
{ !std::invoke(kernel, view, explorer, queue, tracker) } -> std::convertible_to<bool>;
//{
// *std::invoke(kernel, explorer, queue, tracker)
//} -> std::convertible_to<std::remove_cvref_t<decltype(queue::next(queue))>>;
{
*std::invoke(kernel, view, explorer, queue, tracker)
} -> std::convertible_to<std::remove_cvref_t<decltype(queue::next(queue))>>;
};

template <typename T>
Expand Down Expand Up @@ -144,7 +145,7 @@ namespace sl::graph::detail
{
return std::invoke(
CollectorStrategy{},
view::edges(graph, current),
view::out_edges(graph, node::vertex(current)),
current,
m_NodeFactory,
tracker);
Expand Down Expand Up @@ -241,7 +242,7 @@ namespace sl::graph::detail

template <
concepts::basic_node Node,
concepts::view_for<Node> View,
concepts::basic_graph View,
concepts::queue_for<Node> QueueStrategy,
concepts::tracker_for<node::vertex_t<Node>> TrackingStrategy,
concepts::explorer<Node, View, TrackingStrategy> ExplorationStrategy = default_explorer_t<Node, NodeFactory<Node>>,
Expand Down
3 changes: 1 addition & 2 deletions include/Simple-Utility/graph/UniformCostSearch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ namespace sl::graph::ucs
using CommonNode = CommonRankedNode<Vertex, Rank>;

template <
class View,
concepts::basic_graph View,
concepts::ranked_node Node = CommonNode<edge::vertex_t<view::edge_t<View>>, edge::weight_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>
using Range = IterableTraverser<
detail::BasicTraverser<
Node,
Expand Down
95 changes: 55 additions & 40 deletions include/Simple-Utility/graph/View.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,82 +25,96 @@ namespace sl::graph::view
using edge_t = typename traits<T>::edge_type;

template <typename T>
requires requires { typename T::edge_type; }
&& concepts::edge<typename T::edge_type>
using vertex_t = typename traits<T>::vertex_type;

template <typename T>
requires concepts::readable_vertex_type<T>
&& requires { requires concepts::edge<typename T::edge_type>; }
struct traits<T>
{
using vertex_type = typename T::vertex_type;
using edge_type = typename T::edge_type;
};
}

namespace sl::graph::customize
{
template <typename>
struct edges_fn;
struct out_edges_fn;
}

namespace sl::graph::detail
{
template <typename View, typename Node>
requires requires { customize::edges_fn<View>{}; }
&& std::ranges::input_range<std::invoke_result_t<customize::edges_fn<View>, const View&, const Node&>>
template <typename View>
requires requires { customize::out_edges_fn<View>{}; }
&& std::ranges::input_range<std::invoke_result_t<
customize::out_edges_fn<View>, const View&, const view::vertex_t<View>&>>
&& std::convertible_to<
std::ranges::range_reference_t<std::invoke_result_t<customize::edges_fn<View>, const View&, const Node&>>,
std::ranges::range_reference_t<std::invoke_result_t<
customize::out_edges_fn<View>, const View&, const view::vertex_t<View>&>>,
view::edge_t<View>>
constexpr decltype(auto) edges(
constexpr decltype(auto) out_edges(
const View& view,
const Node& node,
const view::vertex_t<View>& vertex,
const priority_tag<2>
) noexcept(noexcept(customize::edges_fn<View>{}(view, node)))
) noexcept(noexcept(customize::out_edges_fn<View>{}(view, vertex)))
{
return customize::edges_fn<View>{}(view, node);
return customize::out_edges_fn<View>{}(view, vertex);
}

// pleases msvc v142
// ReSharper disable CppRedundantTemplateKeyword
// ReSharper disable CppRedundantTypenameKeyword
template <typename View, typename Node>
requires requires(const View& view, const Node& node)
template <typename View>
requires requires(const View& view, const view::vertex_t<View>& vertex)
{
{ view.edges(node) } -> std::ranges::input_range;
{ view.out_edges(vertex) } -> std::ranges::input_range;
requires std::convertible_to<
std::ranges::range_reference_t<decltype(view.edges(node))>,
std::ranges::range_reference_t<decltype(view.out_edges(vertex))>,
typename view::template edge_t<View>>;
}
constexpr decltype(auto) edges(const View& view, const Node& node, const priority_tag<1>) noexcept(noexcept(view.edges(node)))
constexpr decltype(auto) out_edges(
const View& view,
const view::vertex_t<View>& vertex,
const priority_tag<1>
) noexcept(noexcept(view.out_edges(vertex)))
{
return view.edges(node);
return view.out_edges(vertex);
}

template <typename View, typename Node>
requires requires(const View& view, const Node& node)
template <typename View>
requires requires(const View& view, const view::vertex_t<View>& vertex)
{
{ edges(view, node) } -> std::ranges::input_range;
{ out_edges(view, vertex) } -> std::ranges::input_range;
requires std::convertible_to<
std::ranges::range_reference_t<decltype(edges(view, node))>,
std::ranges::range_reference_t<decltype(out_edges(view, vertex))>,
typename view::template edge_t<View>>;
}
constexpr decltype(auto) edges(const View& view, const Node& node, const priority_tag<0>) noexcept(noexcept(edges(view, node)))
constexpr decltype(auto) out_edges(
const View& view,
const view::vertex_t<View>& vertex,
const priority_tag<0>
) noexcept(noexcept(out_edges(view, vertex)))
{
return edges(view, node);
return out_edges(view, vertex);
}

struct edges_fn
struct out_edges_fn
{
template <typename View, typename Node>
requires requires(const View& view, const Node& node, const priority_tag<2> tag)
template <typename View>
requires requires(const View& view, const view::vertex_t<View>& vertex, const priority_tag<2> tag)
{
{ detail::edges(view, node, tag) } -> std::ranges::input_range;
{ detail::out_edges(view, vertex, tag) } -> std::ranges::input_range;
requires std::convertible_to<
std::ranges::range_reference_t<decltype(detail::edges(view, node, tag))>,
std::ranges::range_reference_t<decltype(detail::out_edges(view, vertex, tag))>,
typename view::template edge_t<View>>;
}
constexpr decltype(auto) operator ()(
const View& view,
const Node& node
) const noexcept(noexcept(detail::edges(view, node, priority_tag<2>{})))
const view::vertex_t<View>& vertex
) const noexcept(noexcept(detail::out_edges(view, vertex, priority_tag<2>{})))
{
return detail::edges(view, node, priority_tag<2>{});
return detail::out_edges(view, vertex, priority_tag<2>{});
}
};

Expand All @@ -110,24 +124,25 @@ namespace sl::graph::detail

namespace sl::graph::view
{
inline constexpr detail::edges_fn edges{};
inline constexpr detail::out_edges_fn out_edges{};
}

namespace sl::graph::concepts
{
template <typename T, typename Node>
concept view_for = basic_node<Node>
&& sl::concepts::unqualified<T>
&& requires(const T& view, const Node& node)
template <typename T>
concept basic_graph = sl::concepts::unqualified<T>
&& std::destructible<T>
&& requires(const T& view)
{
// fixes compile error on msvc v142
// ReSharper disable CppRedundantTemplateKeyword
// ReSharper disable CppRedundantTypenameKeyword
typename view::template traits<T>::edge_type;
requires edge_for<typename view::template edge_t<T>, Node>;
{ view::edges(view, node) } -> std::ranges::input_range;
requires vertex<typename view::template traits<T>::vertex_type>;
requires edge<typename view::template traits<T>::edge_type>;
{ view::out_edges(view, std::declval<const view::vertex_t<T>&>()) } -> std::ranges::input_range;
requires std::convertible_to<
std::ranges::range_value_t<std::invoke_result_t<detail::edges_fn, const T&, const Node&>>,
std::ranges::range_value_t<std::invoke_result_t<
detail::out_edges_fn, const T&, const view::vertex_t<T>&>>,
typename view::template edge_t<T>>;
// ReSharper restore CppRedundantTemplateKeyword
// ReSharper restore CppRedundantTypenameKeyword
Expand Down
37 changes: 14 additions & 23 deletions tests/graph/Defines.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,27 +118,20 @@ class BasicViewMock
public:
inline static constexpr bool trompeloeil_movable_mock = true;

using edge_type = GenericBasicEdge<Vertex>;

MAKE_CONST_MOCK1(edges, std::vector<edge_type>(const GenericBasicNode<Vertex>&));
using vertex_type = Vertex;
using edge_type = GenericBasicEdge<vertex_type>;

template <sg::concepts::basic_node Node>
requires sg::concepts::edge_for<edge_type, Node>
std::vector<edge_type> edges(const Node& node) const
{
return edges(GenericBasicNode<Vertex>{.vertex = sg::node::vertex(node)});
}
MAKE_CONST_MOCK1(out_edges, std::vector<edge_type>(const vertex_type&));
};

template <sg::concepts::vertex Vertex>
class EmptyViewStub
{
public:
using edge_type = GenericBasicEdge<Vertex>;
using vertex_type = Vertex;
using edge_type = GenericBasicEdge<vertex_type>;

template <sg::concepts::basic_node Node>
requires sg::concepts::edge_for<edge_type, Node>
static constexpr std::array<edge_type, 0> edges([[maybe_unused]] const Node& node) noexcept
static constexpr std::array<edge_type, 0> out_edges([[maybe_unused]] const vertex_type&) noexcept
{
return {};
}
Expand All @@ -160,13 +153,12 @@ inline static const std::unordered_map<int, std::vector<int>> graph{

struct BasicViewStub
{
using edge_type = sg::CommonBasicEdge<std::string>;
using vertex_type = std::string;
using edge_type = sg::CommonBasicEdge<vertex_type>;

template <sg::concepts::basic_node Node>
requires sg::concepts::edge_for<edge_type, Node>
static std::vector<edge_type> edges(const Node& current)
static std::vector<edge_type> out_edges(const vertex_type& current)
{
const auto vertex = std::stoi(sg::node::vertex(current));
const auto vertex = std::stoi(current);
if (!graph.contains(vertex))
{
return {};
Expand All @@ -185,13 +177,12 @@ struct BasicViewStub

struct WeightedViewStub
{
using vertex_type = std::string;
using edge_type = sg::CommonWeightedEdge<std::string, int>;

template <sg::concepts::basic_node Node>
requires sg::concepts::edge_for<edge_type, Node>
static std::vector<edge_type> edges(const Node& current)
static std::vector<edge_type> out_edges(const vertex_type& current)
{
const auto vertex = std::stoi(sg::node::vertex(current));
const auto vertex = std::stoi(current);
if (!graph.contains(vertex))
{
return {};
Expand All @@ -207,7 +198,7 @@ struct WeightedViewStub
{
return edge_type{
.destination = std::to_string(v),
.weight = std::abs(v - std::stoi(current.vertex))
.weight = std::abs(v - vertex)
};
});
return infos;
Expand Down
4 changes: 2 additions & 2 deletions tests/graph/Traverse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ TEMPLATE_LIST_TEST_CASE(
const BasicViewMock<int> view{};
// clang, honestly. I hate you. This workaround is necessary for the whole range clang[11, 14] + clangCl
const std::vector<DefaultEdge>& edgeCollectionRef = edgeCollection;
REQUIRE_CALL(view, edges(current))
REQUIRE_CALL(view, out_edges(sg::node::vertex(current)))
.LR_RETURN(edgeCollectionRef);

NodeFactoryMock<DefaultNode, DefaultEdge> nodeFactory{};
Expand Down Expand Up @@ -254,7 +254,7 @@ TEST_CASE("detail::BasicTraverser::next returns the current node, or std::nullop
SECTION("Next returns a node, when queue contains elements.")
{
// vertex 43 will be skipped on purpose
REQUIRE_CALL(view, edges(originNode))
REQUIRE_CALL(view, out_edges(sg::node::vertex(originNode)))
.RETURN(std::vector<VertexInfo>{{41}, {43}, {44}});

REQUIRE_CALL(queue, do_insert(matches(RangeEquals(std::vector<DefaultNode>{{41}, {44}}))));
Expand Down
Loading

0 comments on commit 2c8b2e4

Please sign in to comment.